OpenCV学习笔记(十一)

it2023-02-18  79

映射变化:

重映射:

顾名思义,重映射,重新映射的意思,就是把一幅图像的某个位置的像素放置到另一个图片指定的位置的过程

为了完成重映射过程有必要获得一些插值作为非整数像素坐标,因为原图像与目标图像的像素坐标不是一一对应的。我们通过重映射来表达每个像素的位置(x, y):

这样就是按x轴方向发生翻转:

函数原型:

void cv::remap ( InputArray src, OutputArray dst, InputArray map1, InputArray map2, int interpolation, int borderMode = BORDER_CONSTANT, const Scalar & borderValue = Scalar() )

一参二参为输入输出图像,

三参四参. map1: (x, y)的第一个映射或者是CV_16SC2、CV_32FC1或CV_32FC2的x值。查询convertMaps获得详细解释。 . map2: 第二个map,表示类型为CV_16UC1、CV_32FC1的y值或空值(如果map1是用(x,y)进行表示)

五参为插值方式标识符:

六参七参为边界模式,边界值

map1 代表的是在原位置的列号,map2 是行号

测试程序:

#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; int main(int argc, char** argv) { Mat src = imread("E://hashiqi.jpg"); imshow("1",src); Mat dst; Mat map_x, map_y; dst.create(src.size(), src.type()); map_x.create(src.size(), CV_32FC1); map_y.create(src.size(), CV_32FC1); for (int j = 0; j < src.rows; j++) { for (int i = 0; i < src.cols; i++) { //改变map_x & map_y的值. map_x.at<float>(j, i) = static_cast<float>(src.cols - i); map_y.at<float>(j, i) = static_cast<float>(j); } } remap(src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0)); imshow("2", dst); waitKey(0); }

测试结果:

换个映射函数:

map_x.at<float>(j, i) = static_cast<float>(i); map_y.at<float>(j, i) = static_cast<float>(src.rows-j);

仿射变换:

又称仿射映射,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程中,它保持了二维图形的“平直性”(直线变换后还是直线)和”平行性“(二维图形之间的相对位置关系保持不变,平行线依然是平行线,且直线上面的点顺序不变)

一个任意的仿射变换都能表示为乘一个矩阵(线性变换)接着再加上一个向量(平移)

旋转,平移,缩放

利用opencv实现仿射变换一般会涉及到warpAffine和getRotationMatrix2D两个函数,其中warpAffine可以实现一些简单的重映射,而getRotationMatrix2D可以获得旋转矩阵。

void cv::warpAffine ( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar & borderValue = Scalar() )

. src: 输入图像 . dst: 输出图像,尺寸由dsize指定,图像类型与原图像一致 . M: 2X3的变换矩阵 . dsize: 指定图像输出尺寸 . flags: 插值算法标识符,有默认值INTER_LINEAR,如果插值算法为WARP_INVERSE_MAP, warpAffine函数使用如下矩阵进行图像转换

测试程序:

#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> using namespace cv; using namespace std; #define WINDOW_NAME1 "【原始图窗口】" #define WINDOW_NAME2 "【经过Warp后的图像】" #define WINDOW_NAME3 "【经过Warp和Rotate后的图像】" int main() { system("color 1F"); //【1】参数准备 //定义两组二维点,代表两个三角形 Point2f srcTriangle[3]; Point2f dstTriangle[3]; //定义一些Mat变量 Mat rotMat(2, 3, CV_32FC1); Mat warpMat(2, 3, CV_32FC1); Mat srcImage, dstImage_warp, dstImage_warp_rotate; //【2】加载源图像并作一些初始化 srcImage = imread("E://hashiqi.jpg", 1); dstImage_warp = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type()); //【3】设置源图像和目标图像上的三组点以计算仿射变换 srcTriangle[0] = Point2f(0, 0); srcTriangle[1] = Point2f(static_cast<float>(srcImage.cols - 1), 0); srcTriangle[2] = Point2f(0, static_cast<float>(srcImage.rows - 1)); dstTriangle[0] = Point2f(static_cast<float>(srcImage.cols * 0.0), static_cast<float>(srcImage.rows * 0.33)); dstTriangle[1] = Point2f(static_cast<float>(srcImage.cols * 0.65), static_cast<float>(srcImage.rows * 0.35)); dstTriangle[2] = Point2f(static_cast<float>(srcImage.cols * 0.15), static_cast<float>(srcImage.rows * 0.6)); //【4】求得仿射变换 warpMat = getAffineTransform(srcTriangle, dstTriangle); //【5】对源图像应用刚刚求得的仿射变换 warpAffine(srcImage, dstImage_warp, warpMat, dstImage_warp.size()); //【6】对图像进行缩放后再旋转 // 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵 Point center = Point(dstImage_warp.cols / 2, dstImage_warp.rows / 2); double angle = -50.0; double scale = 0.6; // 通过上面的旋转细节信息求得旋转矩阵 rotMat = getRotationMatrix2D(center, angle, scale); // 旋转已缩放后的图像 warpAffine(dstImage_warp, dstImage_warp_rotate, rotMat, dstImage_warp.size()); //【7】显示结果 imshow(WINDOW_NAME1, srcImage); imshow(WINDOW_NAME2, dstImage_warp); imshow(WINDOW_NAME3, dstImage_warp_rotate); // 等待用户按任意按键退出程序 waitKey(0); return 0; }

测试结果:

直方图均衡化:

主要用于扩大图像的动态范围,看这篇,写的非常好https://www.jianshu.com/p/902126aa054e

opencv中直方图均衡的函数特别简单,只有输入输出图像两个参数

函数原型:

void equalizeHist(InputArray src,OutputArray dst)

注意的是,输入图像必须为灰度图像

测试程序:

#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; int main(int argc, char** argv) { Mat src, temp, dst; src = imread("E://1.jpg"); imshow("1", src); cvtColor(src, temp, COLOR_BGR2GRAY); equalizeHist(temp, dst); imshow("2", dst); waitKey(0); }

测试结果:

猜想彩色图像的直方图均衡化,是将图像的每个通道均衡,然后合并,以后验证

 

最新回复(0)