C#描述-计算机视觉OpenCV(3):重映射

C#描述-计算机视觉OpenCV(3):重映射

前言

C#描述-计算机视觉OpenCV(1):基础操作
C#描述-计算机视觉OpenCV(2):图像处理

在前文中,描述了如何对像素和图像进行基本的运算与处理,结合图像的原理,我们已经可以做出很多操作了。这里我们先做一个热身,如何将一张胶卷的负片转换为正片。

胶卷作为一种古早的记录图像的工具,有正负两种格式,正片与我们肉眼所见色彩一致。那么负片,也就是我们印象中最常见到的胶片,看起来明暗是相反的,其色彩为被摄体的补色,其中,负片的负的含义,就是RGB码取了余数。

知道了原理,我们就可以很轻松的来写一个扫描负片的方法:

csharp 复制代码
int r = img.Rows;
int c = img.Cols;
Cv2.ImShow("win0", img);
for (int i = 0; i < r; i++)
   for (int j = 0; j < c; j++)
                {
                    img.At<Vec3b>(i, j)[0] = (byte)(255-img.At<Vec3b>(i, j)[0]);
                    img.At<Vec3b>(i, j)[1] = (byte)(255-img.At<Vec3b>(i, j)[1]);
                    img.At<Vec3b>(i, j)[2] = (byte)(255-img.At<Vec3b>(i, j)[2]);
                }
Cv2.ImShow("win1", img);

结果如图,这就是我们现实中扫描前与扫描后的胶卷底片的差异。学习OpenCV不只是要去机械的学习算法与代码,要结合实际的运用,才能具象的理解算法的原理与作用。

色彩波形

对于一个图案内部的色彩变化,我们可以借助取出行列的RGB波形来研究:

先去定义一个Chart与加载一套list(一式三份,对应RGB),再输出

csharp 复制代码
for (int j = 0; j < Max; j++)
            {
                int r = 50;//对(50,j)进行扫描读取
                string str;
                str = Convert.ToString(j) + ":" + Convert.ToString(img.At<Vec3b>(50, j)[0]) + "/ " + Convert.ToString(img.At<Vec3b>(50, j)[1]) + "/ " + Convert.ToString(img.At<Vec3b>(50, j)[2]);
                textBox1.Text += str + "\r\n";

                XList1.Add(j);
                YList1.Add(img.At<Vec3b>(r, j)[1]);
                chart1.Series["Green"].Points.DataBindXY(XList1, YList1);
                XList2.Add(j);
                YList2.Add(img.At<Vec3b>(r, j)[2]);
                chart1.Series["Blue"].Points.DataBindXY(XList2, YList2);
                XList.Add(j);
                YList.Add(img.At<Vec3b>(r, j)[0]);
                chart1.Series["Red"].Points.DataBindXY(XList, YList);
            }

效果:

当我们分析渐变色区域的时候,我们可以借助这个方法来分析图像的色彩区间。

图像重映射

重映射是通过移动像素修改图像的外观。这个过程不会修改像素值,而是把每个像素的位置重新映射到新的位置 。那么其实我们常用的图像翻转也是重映射的方法,同时我们还可以用这个方法来制作特效与扭曲图像。

重映射运用到的方法是Remap,

remap(image, // 源图像

result, // 目标图像

srcX, // x 映射

srcY, // y 映射

cv::INTER_LINEAR); // 填补方法

}

无论什么语言下的OpenCv都可以调用这个方法,参数也是一样的。

其中,img为待修改Mat原图,result为结果保存到的Mat图片,srcX和Y是映射Mat矩阵,填补方法是像素插值法,可以重载暂时不管。

那么我们来声明三组参数:

csharp 复制代码
Mat res;
Mat srcX;
Mat srcY;
res=new Mat(image.Rows,image.Cols, image.Type());
srcX = new Mat(image.Rows, image.Cols, MatType.CV_32F);
srcY = new Mat(image.Rows, image.Cols, MatType.CV_32F);

其中,MatType.CV_32F是Mat的数据类型,对应着占32位的float。

然后我们需要写一个循环,来布置映射矩阵,以实现图像的翻转:

csharp 复制代码
for (int i = 0; i < image.Rows; i++)
            {
                for (int j = 0; j < image.Cols; j++)
                {
                    // (i,j)像素的新位置
                    srcX.At<float>(j, i) = i;                        // 行不变(X不变)
                    srcY.At<float>(j, i) = image.Rows-j;      // 列翻转(Y翻转不变)
                }
            }

映射矩阵的作用是告诉remap像素移动的方式或者说位置,可以说,映射的算法都由映射矩阵来实现。写完映射矩阵,我们就可以直接调用Cv2.Remap()了。

再例如,我们对图像做一个波浪形映射,运用三角函数来运算映射矩阵:

效果图:

完整代码:

csharp 复制代码
 public void test(Mat image)
        {
             Mat res;
             Mat srcX;
             Mat srcY;
            res=new Mat(image.Rows,image.Cols, image.Type());
            srcX = new Mat(image.Rows, image.Cols, MatType.CV_32F);
            srcY = new Mat(image.Rows, image.Cols, MatType.CV_32F);
            for (int i = 0; i < image.Rows; i++)
            {
                for (int j = 0; j < image.Cols; j++)
                {
                    // (i,j)像素的新位置
                    srcX.At<float>(i,j) = j;//j; // 保持在同一列
                                             // 原来在第 i 行的像素,现在根据一个正弦曲线移动
                    srcY.At<float>(i, j) = i + 5 * (float)(Math.Sin(j / 10.0));
                }
            }
            Cv2.Remap(image, res, srcX, srcY);
            Cv2.ImShow("win1", res);
            Cv2.ImShow("win0", image);
        }

在这其中,sin控制了扭曲的波形,x*sin为波形的幅度

2倍正弦波:

6倍正弦波:

相关推荐
只怕自己不够好10 分钟前
OpenCV 图像运算全解析:加法、位运算(与、异或)在图像处理中的奇妙应用
图像处理·人工智能·opencv
神仙别闹26 分钟前
基于C#和Sql Server 2008实现的(WinForm)订单生成系统
开发语言·c#
华清远见IT开放实验室2 小时前
【每天学点AI】实战图像增强技术在人工智能图像处理中的应用
图像处理·人工智能·python·opencv·计算机视觉
只怕自己不够好2 小时前
《OpenCV 图像缩放、翻转与变换全攻略:从基础操作到高级应用实战》
人工智能·opencv·计算机视觉
HPC_fac130520678165 小时前
以科学计算为切入点:剖析英伟达服务器过热难题
服务器·人工智能·深度学习·机器学习·计算机视觉·数据挖掘·gpu算力
安静读书8 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
小陈phd8 小时前
OpenCV从入门到精通实战(九)——基于dlib的疲劳监测 ear计算
人工智能·opencv·计算机视觉
向宇it10 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
九鼎科技-Leo10 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
Heaphaestus,RC11 小时前
【Unity3D】获取 GameObject 的完整层级结构
unity·c#