赞
踩
补充:超分辨率缩放可实现图像不失真
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Emgu.CV; using Emgu.CV.Structure; using Emgu.CV.CvEnum; using Emgu.Util; using System.Drawing; namespace Lesson12 { class Program { static void Main(string[] args) { #region 图像缩放---Resize //Mat srcImg = CvInvoke.Imread("opencv.jpg"); //CvInvoke.Imshow("src", srcImg); /超分辨率,可实现无失真缩放 //Mat dstImg = new Mat(); //CvInvoke.Resize(srcImg, dstImg, new Size(600, 400)); CvInvoke.Resize(srcImg, dstImg, new Size(), 0.5, 0.5); //CvInvoke.Imshow("dst", dstImg); //CvInvoke.WaitKey(0); #endregion #region 图像平移 //Image<Bgr, Byte> srcImg = new Image<Bgr, Byte>("1.jpg"); //CvInvoke.Imshow("src", srcImg); //int xOffset = 100, yOffset = 100; 不改变图像大小,信息会丢失) int dstRows = srcImg.Rows; int dstCols = srcImg.Cols; 会改变图像大小,信息不丢失) //int dstRows = srcImg.Rows + Math.Abs(yOffset); //int dstCols = srcImg.Cols + Math.Abs(xOffset); //Image<Bgr, Byte> dstImg = new Image<Bgr, Byte>(dstCols, dstRows); //ImgTranslate(srcImg, dstImg, xOffset, yOffset); //CvInvoke.Imshow("dst", dstImg); //CvInvoke.WaitKey(0); #endregion #region 图像旋转 //Mat srcImg = CvInvoke.Imread("1.jpg"); //PointF center = new PointF(srcImg.Cols / 2, srcImg.Rows / 2); //double angle = 45; //double scale = 1; //Mat rotateMat = new Mat(); //CvInvoke.GetRotationMatrix2D(center, angle, scale, rotateMat);//获取旋转矩阵 //Mat dstImg = new Mat(); //CvInvoke.WarpAffine(srcImg, dstImg, rotateMat, new Size(srcImg.Cols, srcImg.Rows));//进行仿射变换 //CvInvoke.Imshow("dst", dstImg); //CvInvoke.WaitKey(0); #endregion #region 转置镜像 Mat srcImg = CvInvoke.Imread("lena.jpg"); CvInvoke.Imshow("src", srcImg); Mat dstImg = new Mat(); //CvInvoke.Flip(srcImg, dstImg, FlipType.None); //X CvInvoke.Flip(srcImg, dstImg, FlipType.Horizontal); //Y //CvInvoke.Flip(srcImg, dstImg, FlipType.Vertical); //X CvInvoke.Transpose(dstImg, dstImg); //行列相反 CvInvoke.Imshow("dst", dstImg); CvInvoke.WaitKey(0); #endregion #region 重映射 //Image<Bgr, Byte> srcImg = new Image<Bgr, Byte>("lena.jpg"); //CvInvoke.Imshow("src", srcImg); //Image<Gray, Single> xMatImg = new Image<Gray, Single>(srcImg.Cols, srcImg.Rows); //Image<Gray, Single> yMatImg = new Image<Gray, Single>(srcImg.Cols, srcImg.Rows); //for (int i = 0; i < srcImg.Rows; i++) //{ // for (int j = 0; j < srcImg.Cols; j++) // { // xMatImg[i, j] = new Gray(j); // yMatImg[i, j] = new Gray(i + 5 * Math.Sin(j / 10.0)); // } //} //Mat dstImg = new Mat(); //CvInvoke.Remap(srcImg, dstImg, xMatImg, yMatImg, Inter.Area); //CvInvoke.Imshow("dst", dstImg); //CvInvoke.WaitKey(0); #endregion } #region 图像平移实现函数 public static void ImgTranslate(Image<Bgr, Byte> srcImg, Image<Bgr, Byte> dstImg, int xOffset, int yOffset) { for (int i = 0; i < srcImg.Rows; i++) { for (int j = 0; j < srcImg.Cols; j++) { int x = j + xOffset; int y = i + yOffset; if (x >= 0 && x < dstImg.Cols && y >= 0 && y < dstImg.Rows) dstImg[y, x] = srcImg[i, j]; } } } #endregion } }
Resize、Flip、Rotate
Resize
图像缩放是把原图像按照目标尺寸放大或者缩小,是图像处理的一种。
图像缩放有多种算法。最为简单的是最临近插值算法,它是根据原图像和目标图像的尺寸,计算缩放的比例,然后根据缩放比例计算目标像素所依据的原像素,过程中自然会产生小数,这时就采用四舍五入,取与这个点最相近的点。
除此之外,还有双线性插值算法。
双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。
其公式如下: f(i+u,j+v) =(1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
其中U和V表示浮点坐标的小数部分,显然离目标点距离越近的点的权重越大,这也正符合目标点的值与离他最近的点最接近这一事实。
cv4j
的resize
目前支持这两种算法。通过Resize
类的源码,可以看到有两个常量
public final static int NEAREST_INTEPOLATE = 1; // 最临近插值算法
public final static int BILINE_INTEPOLATE = 2; // 双线性插值算法
使用最临近插值算法,将原图缩小到0.75倍。
CV4JImage cv4jImage = new CV4JImage(bitmap);
ImageProcessor imageProcessor = cv4jImage.getProcessor();
Resize resize = new Resize(0.75f);
imageProcessor = resize.resize(imageProcessor,Resize.NEAREST_INTEPOLATE);
if (imageProcessor!=null) {
CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
result1.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
使用双线性插值算法,将原图放大2倍。
cv4jImage = new CV4JImage(bitmap);
ImageProcessor imageProcessor2 = cv4jImage.getProcessor();
resize = new Resize(2f);
imageProcessor2 = resize.resize(imageProcessor,Resize.BILINE_INTEPOLATE);
if (imageProcessor2!=null) {
CV4JImage resultCV4JImage = new CV4JImage(imageProcessor2.getWidth(), imageProcessor2.getHeight(), imageProcessor2.getPixels());
result2.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
效果如下:
Flip
Flip
是翻转的意思,也被称为镜像变换。又可以分为水平镜像和垂直镜像,水平镜像即将图像左半部分和右半部分以图像竖直中轴线为中心轴进行兑换,而竖直镜像则是将图像上半部分和下半部分以图像水平中轴线为中心轴进行兑换。
flip
的算法很简单
public final static int FLIP_VERTICAL = -1; public final static int FLIP_HORIZONTAL = 1; public static void flip(ImageProcessor processor, int option) { int width = processor.getWidth(); int height = processor.getHeight(); int ch = processor.getChannels(); int index1 = 0; int index2 = 0; int total = width*height; byte[][] output = new byte[ch][total]; for(int row=0; row<height; row++) { for(int col=0; col<width; col++) { index1 = row*width+col; if(option == FLIP_HORIZONTAL) { index2 = row*width + width-col-1; } else if(option == FLIP_VERTICAL){ index2 = (height-row-1)*width + col; } else { throw new CV4JException("invalid option : " + option); } for(int i=0; i<ch; i++) { output[i][index2] = processor.toByte(i)[index1]; } } } if(ch == 3) { ((ColorProcessor) processor).putRGB(output[0], output[1], output[2]); } else { ((ByteProcessor) processor).putGray(output[0]); } }
实现具体的左右翻转
CV4JImage cv4jImage = new CV4JImage(bitmap);
ImageProcessor imageProcessor = cv4jImage.getProcessor();
Flip.flip(imageProcessor,Flip.FLIP_HORIZONTAL);
if (imageProcessor!=null) {
CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
result1.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
实现具体的上下翻转
cv4jImage = new CV4JImage(bitmap);
ImageProcessor imageProcessor2 = cv4jImage.getProcessor();
Flip.flip(imageProcessor2,Flip.FLIP_VERTICAL);
if (imageProcessor2!=null) {
CV4JImage resultCV4JImage = new CV4JImage(imageProcessor2.getWidth(), imageProcessor2.getHeight(), imageProcessor2.getPixels());
result2.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
效果如下:
Rotate
图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。当然这个点通常就是图像的中心。既然是按照中心旋转,自然会有这样一个属性:旋转前和旋转后的点离中心的位置不变。
图像的旋转是图像几何变换的一种,旋转前后的图像的像素的RGB
都是没有改变的,改变的只是每一个像素的所在位置。
cv4j
提供两种旋转的算法:NormRotate
和FastRotate
下面以NormRotate
为例,使用起来很简单,旋转120
度,背景为红色。
CV4JImage cv4jImage = new CV4JImage(bitmap);
ImageProcessor imageProcessor = cv4jImage.getProcessor();
NormRotate normRotate = new NormRotate();
imageProcessor = normRotate.rotate(imageProcessor,120, Scalar.rgb(255,0,0));
if (imageProcessor!=null) {
CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
}
效果如下:
cv4j
是gloomyfish
和我一起开发的图像处理库,纯java实现,我们已经分离了一个Android版本和一个Java版本。
像素操作是 cv4j
的基本功能之一,本文介绍了三种常见的变换。我们可以通过图像的Resize、Flip、Rotate
变换来丰富图片数据的多样性。
如果您想看该系列先前的文章可以访问下面的文集: www.jianshu.com/nb/10401400
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。