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

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

    • 前言
    • 色彩波形
    • 图像重映射

前言

C#描述-计算机视觉OpenCV(1):基础操作
C#描述-计算机视觉OpenCV(2):图像处理
在前文中,描述了如何对像素和图像进行基本的运算与处理,结合图像的原理,我们已经可以做出很多操作了。这里我们先做一个热身,如何将一张胶卷的负片转换为正片。
胶卷作为一种古早的记录图像的工具,有正负两种格式,正片与我们肉眼所见色彩一致。那么负片,也就是我们印象中最常见到的胶片,看起来明暗是相反的,其色彩为被摄体的补色,其中,负片的负的含义,就是RGB码取了余数。
知道了原理,我们就可以很轻松的来写一个扫描负片的方法:

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),再输出

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矩阵,填补方法是像素插值法,可以重载暂时不管。
那么我们来声明三组参数:

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。
然后我们需要写一个循环,来布置映射矩阵,以实现图像的翻转:

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()了。
再例如,我们对图像做一个波浪形映射,运用三角函数来运算映射矩阵:
效果图:
在这里插入图片描述
完整代码:

 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倍正弦波:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/589599.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2.2 Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3-基础-Vue基本语法

文本渲染指令 文本渲染指令-v-html与v-text Vue使用了基于HTML的模板语法&#xff0c;允许开发者声明式地将DOM绑定至底层Vue实例的数据。所有Vue的模板都是 合法的HTML&#xff0c;所以能被遵循规范的浏览器和HTML解析器解析。 在前面&#xff0c;我们一直使用的是字符串插…

探索科技园区的创新应用架构

在当今科技快速发展的时代&#xff0c;科技园区已经成为了创新和技术发展的孵化器和聚集地。在这样的环境中&#xff0c;科技园区的应用架构扮演着至关重要的角色&#xff0c;它不仅需要支持各种创新型企业和科技项目的发展&#xff0c;还需要提供高效的技术基础设施和服务。下…

python 11Pandas数据可视化实验

实验目的&#xff1a; 学会使用Pandas操作数据集&#xff0c;并进行可视化。 数据集描述&#xff1a; 该数据集是CNKI中与“中药毒理反应”相关的文献信息&#xff0c;包含文章题目、作者、来源&#xff08;出版社&#xff09;、摘要、发表时间等信息。 实验要求&#xff1…

ubuntu外置网卡配置AP模式

外置网卡RTL8811CU设置 UBUNTU使用RTL8811CU网卡&#xff08;包含树莓派&#xff09; 外置网卡配置AP模式流程 1. 检查网卡支持情况&#xff08;是否支持AP模式&#xff09; iw list找到以上部分&#xff0c;发现支持AP 2. 安装依赖 sudo apt-get update sudo apt-get in…

39 死锁

目录 1.死锁 2.线程同步 3.条件变量 4.案例 死锁 概念 死锁是指在一组进程中的各个进程均占有不会释放的资源&#xff0c;但因互相申请被其他进程所占用不会释放的资源而处于的一种永久等待状态 四个必要条件 互斥条件&#xff1a;一个资源每次只能被一个执行流使用 请求…

MFC 列表控件修改实例(源码下载)

1、本程序基于前期我的博客文章《MFC下拉菜单打钩图标存取实例&#xff08;源码下载&#xff09;》 2、程序功能选中列表控件某一项&#xff0c;修改这一项的按钮由禁止变为可用&#xff0c;双击这个按钮弹出对话框可对这一项的记录数据进行修改&#xff0c;点击确定保存修改数…

SpirngBoot整合快递100

目录 一、注册快递100 二、技术文档地址 三、需要认证的key和comcumer 四、spring boot 整合快递 100使用 4.1 引入快递100和hutool的依赖 4.2 将key和comcumer写入application.properties文件中 4.3 新建一个modle,用于将查出来的json数据转成对象 4.4 新建一个controll…

golang 基础知识细节回顾

之前学习golang的速度过于快&#xff0c;部分内容有点囫囵吞枣的感觉&#xff0c;写gorm过程中有很多违反我常识的地方&#xff0c;我通过复习去修正了我之前认知错误和遗漏的地方。 itoa itoa自增的作用在编辑error code时候作用很大&#xff0c;之前编辑springboot的error c…

python从0开始学习

目录 前言 1、print函数 2、input函数 3、保留字和标识符 总结 前言 本篇文章我们开辟一个新的学习模块&#xff1a;python。python是一个十分简洁实用的编程语言&#xff0c;我们将从0开始学习python 1、print函数 print(*args, sep , end\n, fileNone, flushFalse) pytho…

2024五一数学建模C题煤矿深部开采冲击地压危险预测原创论文分享

大家好&#xff0c;从昨天肝到现在&#xff0c;终于完成了2024五一数学建模竞赛C题的完整论文啦。 实在精力有限&#xff0c;具体的讲解大家可以去讲解视频&#xff1a; 2024五一数学建模C题完整原创论文讲解&#xff0c;手把手保姆级教学&#xff01;_哔哩哔哩_bilibili 202…

[1678]旅游景点信息Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 旅游景点信息管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql…

在idea中连接mysql

IDE&#xff08;集成开发环境&#xff09;是一种软件应用程序&#xff0c;它为开发者提供编程语言的开发环境&#xff0c;通常集成了编码、编译、调试和运行程序的多种功能。一个好的IDE可以大幅提高开发效率&#xff0c;尤其是在进行大型项目开发时。IDE通常包括以下几个核心组…

酒水门店私域流量运营搭建执行规划方案

【干货资料持续更新&#xff0c;以防走丢】 酒水门店私域流量运营搭建执行规划方案 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 PPT可编辑&#xff08;完整资料包含以下内容&#xff09; 目录 精酿啤酒品牌私域执行运营的内容策划&#xff0c;涉及以下几个…

在做题中学习(48):朴素的二分查找

. - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a; 暴力求解 for循环中&#xff0c;从nums[0]枚举到nums[n-1]&#xff0c;依次判断&#xff0c;返回 target的值。 时间复杂度 : O(N) :因为要遍历一遍数组 解法二&#xff1a;二分查找 因为此数组为有序的…

利用Github发现优质的学习项目网址

1. 直接搜索&#xff0c;star的数量越多的项目质量越高 2.Github Trending 地址: https://github.com/trending 3. Gitstar Ranking 地址: https://gistar-ranking.com/ 4. Awesome Topic 地址: https://github.com/topics/awesome

FIFO Generate IP核使用——Data Counts页详解

在Vivado IDE中&#xff0c;当看到一个用于设置数据计数选项的选项卡时&#xff0c;需要注意的是&#xff0c;尽管某些选项值可能因为当前的配置而显示为灰色&#xff08;即不可选或已禁用&#xff09;&#xff0c;但IDE中显示的有效范围值实际上是你可以选择的真实值。即使某些…

静态库、动态库回顾

回顾一下库相关的知识点&#xff0c;总结备忘一下。在某种情况下&#xff0c;你有了如下的代码&#xff0c;结构如下 //pra.h #include <stdio.h> void test_01(); //pra.c #include "pra.h" void test_01() {printf("xxxxxxx----->%s %s()\n",…

莫比乌斯变换的数学原理

一、说明 关于莫比乌斯变换&#xff0c;是一个代数几何变换的重要概念。也是双曲几何的重要理论&#xff0c;比如庞加莱盘就是建立在这个理论上&#xff0c;那么这个变换到底有哪些内容&#xff1f;本文将做出详细的解读。 二、线性变换和逆变换 在本节中&#xff0c;我们研…

# notepad++ 编辑器英文版,如何打开自动换行

notepad 编辑器英文版&#xff0c;如何打开自动换行 在Notepad中&#xff0c;如果你想要开启自动换行功能&#xff0c;可以按照以下步骤操作&#xff1a; 1、打开 Notepad 编辑器。 1.1. 依次点击菜单栏中的【视图】&#xff0c;英文版对应【View】。1.2. 在【视图】下拉菜单…

css---浮动知识点精炼汇总

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 浮动简单理解与介绍 这是我们普通的页面标签效果。 每个标签从上到下依次排列。 浮动顾名思义就是让这个标签飞翔起来。 他飞起来后&#xff0c;后面的标签来到他的位置上。 而浮动的标签就会显示在标签的上面。…
最新文章