图像处理(四)图像缩放
来源:互联网 发布:买了淘宝模板怎么修改 编辑:程序博客网 时间:2024/06/06 14:23
图像缩放的定义为:将图像中的某点(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) 所对应的四个像素的值决定:
双线性插值算法计算量比较大,但缩放后图像质量高。由于双线性差值具有低通滤波的性质,使高频分量受损,故会使图像丢失细节变的模糊。
具体算法实现:
/// <summary> /// 图像缩放 /// </summary> /// <param name="srcBmp">原始图像</param> /// <param name="width">目标图像宽度</param> /// <param name="height">目标图像高度</param> /// <param name="dstBmp">目标图像</param> /// <param name="zt">缩放选用的算法</param> /// <returns>处理成功 true 失败 false</returns> 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; }效果图不再展示~
- 图像处理(四)图像缩放
- Delphi图像处理 -- 图像缩放
- 图像缩放处理
- 【OpenCV】图像处理(四)图像金字塔
- C# 图像处理(一)(图像缩放、屏幕截取、图像合并、保存图像)
- 使用 Java 进行图像处理 - 图像缩放
- 图像处理之图像的缩放
- FPGA图像处理系列:图像缩放
- canvas系列--图像处理(三) 图像缩放
- 图像处理14:图像扩展缩放
- FPGA图像处理系列:图像缩放
- 【OpenCV图像处理】四、图像的几何变换(上)
- 图像缩放
- 图像缩放
- 图像缩放
- 图像缩放
- 图像缩放
- 缩放图像
- 代码生成的未来
- 去求1000以内偶数的和
- Flex坐标系统及转换
- switch选择方法实例—数字转换成中文大写
- js不报异常信息
- 图像处理(四)图像缩放
- js 设计模式 第八章 Bridge Pattern
- 流媒体服务器 架设
- 黑马程序员之ASP.NET学习笔记:TREEVIEW中动态增加结点
- 表维护中,怎样把数据下载到本地?
- poj 2752 Seek the Name, Seek the Fame
- 关闭js弹出窗体时,可能会弹出警告
- Android SlidingDrawer 滑动抽屉效果
- OpenGL 4.3 (Core Profile) - August 6, 2012 spec Fundamental 2.3 Command Execution