去除/平滑gd库中的粗糙边缘

Hem*_*dia 3 php gd

我正在使用GD库来动态创建图像.
但是当我使用imagerotate()函数旋转图像时,
它可以正常工作,但它会产生非常刺激的图像
旋转粗糙边缘.
如图所示.
那么如何使旋转图像的这些边/边平滑?
在此输入图像描述

Kuf*_*Kuf 6

避免在旋转图像时获得Jaggies效果的一种方法是使用另一种方法对像素进行采样,而不仅仅是采用调整后的像素,例如使用最近邻插值使边缘更平滑.你可以看到matlab代码示例:

im1 = imread('lena.jpg');imshow(im1);  
[m,n,p]=size(im1);
thet = rand(1);
mm = m*sqrt(2);
nn = n*sqrt(2);
for t=1:mm
   for s=1:nn
      i = uint16((t-mm/2)*cos(thet)+(s-nn/2)*sin(thet)+m/2);
      j = uint16(-(t-mm/2)*sin(thet)+(s-nn/2)*cos(thet)+n/2);
      if i>0 && j>0 && i<=m && j<=n           
         im2(t,s,:)=im1(i,j,:);
      end
   end
end
figure;
imshow(im2);
Run Code Online (Sandbox Code Playgroud)

取自(这里).基本上,这意味着在对原始图片中的像素进行采样时,我们对近像素进行采样并对其进行插值以获得目标像素值.通过这种方式,您可以随意安装任何附加软件包.

编辑

我发现了一些我用Java编写的旧代码,它包含了几个采样算法的实现.这是代码:

最近邻采样器:

/**
 * @pre (this!=null) && (this.pixels!=null)
 * @post returns the sampled pixel of (x,y) by nearest neighbor sampling
 */
private Pixel sampleNearestNeighbor(double x, double y) {
    int X = (int) Math.round(x);
    int Y = (int) Math.round(y);
    if (X >= 0 && Y >= 0 && X < this.pixels.length
            && Y < this.pixels[0].length)
        // (X,Y) is within this.pixels' borders
        return new Pixel(pixels[X][Y].getRGB());
    else
        return new Pixel(255, 255, 255);
    // sample color will be default white
}
Run Code Online (Sandbox Code Playgroud)

双线性采样器:

/**
 * @pre (this!=null) && (this.pixels!=null)
 * @post returns the sampled pixel of (x,y) by bilinear interpolation
 */
private Pixel sampleBilinear(double x, double y) {
    int x1, y1, x2, y2;
    x1 = (int) Math.floor(x);
    y1 = (int) Math.floor(y);
    double weightX = x - x1;
    double weightY = y - y1;
    if (x1 >= 0 && y1 >= 0 && x1 + 1 < this.pixels.length
            && y1 + 1 < this.pixels[0].length) {
        x2 = x1 + 1;
        y2 = y1 + 1;

        double redAX = (weightX * this.pixels[x2][y1].getRed())
                + (1 - weightX) * this.pixels[x1][y1].getRed();
        double greenAX = (weightX * this.pixels[x2][y1].getGreen())
                + (1 - weightX) * this.pixels[x1][y1].getGreen();
        double blueAX = (weightX * this.pixels[x2][y1].getBlue())
                + (1 - weightX) * this.pixels[x1][y1].getBlue();
        // bilinear interpolation of A point

        double redBX = (weightX * this.pixels[x2][y2].getRed())
                + (1 - weightX) * this.pixels[x1][y2].getRed();
        double greenBX = (weightX * this.pixels[x2][y2].getGreen())
                + (1 - weightX) * this.pixels[x1][y2].getGreen();
        double blueBX = (weightX * this.pixels[x2][y2].getBlue())
                + (1 - weightX) * this.pixels[x1][y2].getBlue();
        // bilinear interpolation of B point

        int red = (int) (weightY * redBX + (1 - weightY) * redAX);
        int green = (int) (weightY * greenBX + (1 - weightY) * greenAX);
        int blue = (int) (weightY * blueBX + (1 - weightY) * blueAX);
        // bilinear interpolation of A and B
        return new Pixel(red, green, blue);

    } else if (x1 >= 0
            && y1 >= 0 // last row or column
            && (x1 == this.pixels.length - 1 || y1 == this.pixels[0].length - 1)) {
        return new Pixel(this.pixels[x1][y1].getRed(), this.pixels[x1][y1]
                .getGreen(), this.pixels[x1][y1].getBlue());
    } else
        return new Pixel(255, 255, 255);
    // sample color will be default white
}
Run Code Online (Sandbox Code Playgroud)

高斯采样器:

/**
 * @pre (this!=null) && (this.pixels!=null)
 * @post returns the sampled pixel of (x,y) by gaussian function
 */
private Pixel sampleGaussian(double u, double v) {
    double w = 3; // sampling distance
    double sqrSigma = Math.pow(w / 3.0, 2); // sigma^2
    double normal = 0;
    double red = 0, green = 0, blue = 0;
    double minIX = Math.round(u - w);
    double maxIX = Math.round(u + w);
    double minIY = Math.round(v - w);
    double maxIY = Math.round(v + w);

    for (int ix = (int) minIX; ix <= maxIX; ix++) {
        for (int iy = (int) minIY; iy <= maxIY; iy++) {
            double sqrD = Math.pow(ix - u, 2) + Math.pow(iy - v, 2);
            // squared distance between (ix,iy) and (u,v)
            if (sqrD < Math.pow(w, 2) && ix >= 0 && iy >= 0
                    && ix < pixels.length && iy < pixels[0].length) {
                // gaussian function
                double gaussianWeight = Math.pow(2, -1 * (sqrD / sqrSigma));
                normal += gaussianWeight;
                red += gaussianWeight * pixels[ix][iy].getRed();
                green += gaussianWeight * pixels[ix][iy].getGreen();
                blue += gaussianWeight * pixels[ix][iy].getBlue();
            }
        }
    }
    red /= normal;
    green /= normal;
    blue /= normal;
    return new Pixel(red, green, blue);
}
Run Code Online (Sandbox Code Playgroud)

实际旋转:

     /**
 * @pre (this!=null) && (this.pixels!=null) && (1 <= samplingMethod <= 3)
 * @post creates a new rotated-by-degrees Image and returns it
 */
public myImage rotate(double degrees, int samplingMethod) {
    myImage outputImg = null;

    int t = 0;
    for (; degrees < 0 || degrees >= 180; degrees += (degrees < 0) ? 180
            : -180)
        t++;

    int w = this.pixels.length;
    int h = this.pixels[0].length;
    double cosinus = Math.cos(Math.toRadians(degrees));
    double sinus = Math.sin(Math.toRadians(degrees));

    int width = Math.round((float) (w * Math.abs(cosinus) + h * sinus));
    int height = Math.round((float) (h * Math.abs(cosinus) + w * sinus));

    w--;
    h--; // move from (1,..,k) to (0,..,1-k)

    Pixel[][] pixelsArray = new Pixel[width][height];
    double x = 0; // x coordinate in the source image
    double y = 0; // y coordinate in the source image

    if (degrees >= 90) { // // 270 or 90 degrees turn
        double temp = cosinus;
        cosinus = sinus;
        sinus = -temp;
    }

    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {

            double x0 = i;
            double y0 = j;
            if (degrees >= 90) {
                if ((t % 2 == 1)) { // 270 degrees turn
                    x0 = j;
                    y0 = width - i - 1;
                } else { // 90 degrees turn
                    x0 = height - j - 1;
                    y0 = i;
                }
            } else if (t % 2 == 1) { // 180 degrees turn
                x0 = width - x0 - 1;
                y0 = height - y0 - 1;
            }

            // calculate new x/y coordinates and
            // adjust their locations to the middle of the picture
            x = x0 * cosinus - (y0 - sinus * w) * sinus;
            y = x0 * sinus + (y0 - sinus * w) * cosinus;

            if (x < -0.5 || x > w + 0.5 || y < -0.5 || y > h + 0.5)
                // the pixels that does not have a source will be painted in
                // default white
                pixelsArray[i][j] = new Pixel(255, 255, 255);
            else {
                if (samplingMethod == 1)
                    pixelsArray[i][j] = sampleNearestNeighbor(x, y);
                else if (samplingMethod == 2)
                    pixelsArray[i][j] = sampleBilinear(x, y);
                else if (samplingMethod == 3)
                    pixelsArray[i][j] = sampleGaussian(x, y);
            }
        }
        outputImg = new myImage(pixelsArray);
    }

    return outputImg;
}
Run Code Online (Sandbox Code Playgroud)