图像处理(四)图像缩放

图像缩放的定义为:将图像中的某点(x,y)经缩放后其位置变为(x’,y’),则两者之间的关系为:

                                                        X’= ax   y’ = by

a、b分别是x、y方向上的缩放比例。当a、b大于1时图像放大,小于1时,图像缩小。当a = -1,b = 1时会产生一个关于y轴对称的镜像;当a = 1, b=-1时,会产生一个关于x 轴对称的镜像。其矩阵表示为:

                  

最近邻插值法,是最简单的插值法。其做法是令输出像素的灰度值等于离它所映射到的位置最近的输入图像像素的灰度值。此方法会产生锯齿,放大倍数过大会出现马赛克。

双线性插值也称为一阶差值,此方法是求得相邻的四个相邻的点的距离之比,用这个比率和四个相邻像素点的灰度值进行差值。具体方法如下:对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为f(i+u,j+v),其中i, j均为非负整数,p、q为区间[0,1)的浮点数,则这个像素f(i+p,j+q) 的值可由原图像坐标为( i , j ), (i+1, j), (i, j+1), (i+1 ,j+1) 所对应的四个像素的值决定:

                                        

双线性插值算法计算量比较大,但缩放后图像质量高。由于双线性差值具有低通滤波的性质,使高频分量受损,故会使图像丢失细节变的模糊。

具体算法实现:

  /// 
    /// 图像缩放
    /// 
    /// 原始图像
    /// 目标图像宽度
    /// 目标图像高度
    /// 目标图像
    /// 缩放选用的算法
    /// 处理成功 true 失败 false
    public static bool Zoom(Bitmap srcBmp, double width, double height, out Bitmap dstBmp, ZoomType zt) {//ZoomType为自定义的枚举类型
        if (srcBmp == null) {
            dstBmp = null;
            return false;
        }
        //若缩放大小与原图一样,则返回原图不做处理
        if (srcBmp.Width == width && srcBmp.Height == height) {
            dstBmp = new Bitmap(srcBmp);
            return true;
        }
        //计算缩放比例
        double ratioH = height / (double)srcBmp.Height;
        double ratioW = width / (double)srcBmp.Width;
        dstBmp = new Bitmap((int)width, (int)height);

        BitmapData srcBmpData = srcBmp.LockBits(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        BitmapData dstBmpData = dstBmp.LockBits(new Rectangle(0, 0, dstBmp.Width, dstBmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
        unsafe {
            byte* srcPtr = null;
            byte* dstPtr = null;
            int srcI = 0;
            int srcJ = 0;
            double srcdI = 0;
            double srcdJ = 0;
            double a = 0;
            double b = 0;
            double F1 = 0;//横向插值所得数值
            double F2 = 0;//纵向插值所得数值
            if (zt == ZoomType.NearestNeighborInterpolation) {//邻近插值法

                for (int i = 0; i < dstBmp.Height; i++) {
                    srcI = (int)(i / ratioH);
                    srcPtr = (byte*)srcBmpData.Scan0 + srcI * srcBmpData.Stride;
                    dstPtr = (byte*)dstBmpData.Scan0 + i * dstBmpData.Stride;
                    for (int j = 0; j < dstBmp.Width; j++) {
                        dstPtr[j * 3] = srcPtr[(int)(j / ratioW) * 3];
                        dstPtr[j * 3 + 1] = srcPtr[(int)(j / ratioW) * 3 + 1];
                        dstPtr[j * 3 + 2] = srcPtr[(int)(j / ratioW) * 3 + 2];
                    }
                }
            }
            if (zt == ZoomType.BilinearInterpolation) {//双线性插值法
                byte* srcPtrNext = null;
                for (int i = 0; i < dstBmp.Height; i++) {
                    srcdI = i / ratioH;
                    srcI = (int)srcdI;//当前行对应原始图像的行数
                    srcPtr = (byte*)srcBmpData.Scan0 + srcI * srcBmpData.Stride;//指原始图像的当前行
                    srcPtrNext = (byte*)srcBmpData.Scan0 + (srcI + 1) * srcBmpData.Stride;//指向原始图像的下一行
                    dstPtr = (byte*)dstBmpData.Scan0 + i * dstBmpData.Stride;//指向当前图像的当前行
                    for (int j = 0; j < dstBmp.Width; j++) {
                        srcdJ = j / ratioW;
                        srcJ = (int)srcdJ;//指向原始图像的列
                        if (srcdJ < 1 || srcdJ > srcBmp.Width - 1 || srcdI < 1 || srcdI > srcBmp.Height - 1) {//避免溢出(也可使用循环延拓)
                            dstPtr[j * 3] = 255;
                            dstPtr[j * 3 + 1] = 255;
                            dstPtr[j * 3 + 2] = 255;
                            continue;
                        }
                        a = srcdI - srcI;//计算插入的像素与原始像素距离(决定相邻像素的灰度所占的比例)
                        b = srcdJ - srcJ;
                        for (int k = 0; k < 3; k++) {//插值
                            F1 = (1 - b) * srcPtr[srcJ * 3 + k] + b * srcPtr[(srcJ + 1) * 3 + k];
                            F2 = (1 - b) * srcPtrNext[srcJ * 3 + k] + b * srcPtrNext[(srcJ + 1) * 3 + k];
                            dstPtr[j * 3 + k] = (byte)((1 - a) * F1 + a * F2);
                        }
                    }
                }
            }
        }
        srcBmp.UnlockBits(srcBmpData);
        dstBmp.UnlockBits(dstBmpData);
        return true;
    }
效果图不再展示~

你可能感兴趣的:(图像处理,算法)