【小白】Open-CV 学习笔记 - 7.3 - 7.5 重映射、仿射变换、直方图均衡化

重映射

就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。

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

在这里插入图片描述
在这里插入图片描述

#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
	Mat srcImage = imread("D:\\visual studio 2010\\Projects\\remap\\1.jpg");
	Mat dstImage,map_x,map_y;
	imshow("",srcImage);
	//创建和原始图像一样的效果图,x重映射图,y重映射图
	dstImage.create(srcImage.size(),srcImage.type());
	map_x.create(srcImage.size(),CV_32FC1);
	map_y.create(srcImage.size(),CV_32FC1);
	//双层循环,遍历每一个像素点,改变map_x和map_y的值
	for(int j=0;j<srcImage.rows;j++)
	{
		for(int i=0;i<srcImage.cols ;i++)
		{
			//改变map_x和map_y的值
			map_x.at<float>(j,i) = static_cast<float>(srcImage.rows -i);
			map_y.at<float>(j,i) = static_cast<float>( srcImage.rows-j);
		}
	}
	//进行重映射操作
	remap(srcImage,dstImage,map_x,map_y,CV_INTER_LINEAR,BORDER_CONSTANT,Scalar(255,0,0));
    //显示效果图
	imshow("效果图",dstImage);
	waitKey(0);
	return 0;
 
}

在这里插入图片描述

  • 将第二个for循环修改为
for(int i=0;i<srcImage.cols ;i++)
		{
			//改变map_x和map_y的值
			//水平对称
			map_x.at<float>(j,i) = static_cast<float>( i);
			map_y.at<float>(j,i) = static_cast<float>( srcImage.rows-j);
		}

在这里插入图片描述

  • 将第二个for循环修改为:
for(int i=0;i<srcImage.cols ;i++)
		{
			//改变map_x和map_y的值
			//垂直对称
			map_x.at<float>(j,i) = static_cast<float>(srcImage.rows -i);
			map_y.at<float>(j,i) = static_cast<float>(j);
		}

在这里插入图片描述

仿射变换

仿射变换(Affine Transformation or Affine Map)又称仿射映射。在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。保持二维图像的“平直性”和“平行性”
一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)再加上一个向量(平移)的形式
常用的三种常见的变换形式

  • 旋转,rotation(线性变换)
  • 平移,translation向量加
  • 缩放,scale线性变换

事实上,仿射变换代表的是两幅图之间的关系,我们通常使用2x3矩阵来表示仿射变换如下:
在这里插入图片描述

仿射变换求法

从上面解释中我们得知仿射变换表示的就是两幅图片的一种联系,关于这种联系的信息大致可以从以下两种场景获得。
a. 我们已知X和T而且我们知道他们是有联系的,接下来的工作就是求解矩阵M
b. 我们一致M和X要求得T,我们只需要应用算式T=M.X即可。对于这种联系的信息可以用矩阵M清晰的表达(即给出明确的2x3矩阵)或者也可以用两幅图片点之间几何关系来表达。

因为矩阵M联系着两幅图片,我们以其表示两图中各三点直接的联系为例,如下:
在这里插入图片描述
点1,2和3(在图一中形成一个三角)与图二中三个点一一映射,仍然形成三角形,但形状已经大大改变。如果我们能通过这样两组三点求出仿射变换(你能选择自己喜欢的点),接下来我们就能把仿射变换应用到图像中所有的点。

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

参数解释

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

计算二维旋转变换矩阵:getRotationMatrix2D()函数

Mat getRotationMatrix2D(Point2f center,double angle,double scale)

参数解释

  • center: Point2f类型,表示原图像的旋转中心
  • angle: double类型,表示图像旋转角度,角度为正则表示逆时针旋转,角度为负表示逆时针旋转(坐标原点是图像左上角)
  • scale: 缩放系数
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

using namespace std;
using namespace cv;

//全局变量
String src_windowName = "原图像";
String warp_windowName = "仿射变换";
String warp_rotate_windowName = "仿射旋转变换";
String rotate_windowName = "图像旋转";

int main()
{
    Point2f srcTri[3];
    Point2f dstTri[3];

    Mat rot_mat(2, 3, CV_32FC1);
    Mat warp_mat(2, 3, CV_32FC1);
    Mat srcImage, warp_dstImage, warp_rotate_dstImage, rotate_dstImage;

    //加载图像
    srcImage = imread("dog.jpg");

    //判断文件是否加载成功
    if(srcImage.empty())
    {
        cout << "图像加载失败!" << endl;
        return -1;
    }
    else
        cout << "图像加载成功!" << endl << endl;

    //创建仿射变换目标图像与原图像尺寸类型相同
    warp_dstImage = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type());

    //设置三个点来计算仿射变换
    srcTri[0] = Point2f(0, 0);
    srcTri[1] = Point2f(srcImage.cols - 1, 0);
    srcTri[2] = Point2f(0, srcImage.rows - 1);

    dstTri[0] = Point2f(srcImage.cols*0.0, srcImage.rows*0.33);
    dstTri[1] = Point2f(srcImage.cols*0.85, srcImage.rows*0.25);
    dstTri[2] = Point2f(srcImage.cols*0.15, srcImage.rows*0.7);

    //计算仿射变换矩阵
    warp_mat = getAffineTransform(srcTri, dstTri);

    //对加载图形进行仿射变换操作
    warpAffine(srcImage, warp_dstImage, warp_mat, warp_dstImage.size());

    //计算图像中点顺时针旋转50度,缩放因子为0.6的旋转矩阵
    Point center = Point(warp_dstImage.cols/2, warp_dstImage.rows/2);
    double angle = -50.0;
    double scale = 0.6;

    //计算旋转矩阵
    rot_mat = getRotationMatrix2D(center, angle, scale);

    //旋转已扭曲图像
    warpAffine(warp_dstImage, warp_rotate_dstImage, rot_mat, warp_dstImage.size());

    //将原图像旋转
    warpAffine(srcImage, rotate_dstImage, rot_mat, srcImage.size());

    //显示变换结果
    namedWindow(src_windowName, WINDOW_AUTOSIZE);
    imshow(src_windowName, srcImage);

    namedWindow(warp_windowName, WINDOW_AUTOSIZE);
    imshow(warp_windowName, warp_dstImage);

    namedWindow(warp_rotate_windowName, WINDOW_AUTOSIZE);
    imshow(warp_rotate_windowName, warp_rotate_dstImage);

    namedWindow(rotate_windowName, WINDOW_AUTOSIZE);
    imshow(rotate_windowName, rotate_dstImage);

    waitKey(0);

    return 0;
}

在这里插入图片描述
在这里插入图片描述

equalizeHist 直方图均衡化

函数功能:

直方图均衡化,该函数能归一化图像亮度和增强对比度

OpenCV官网的图像很形象,这里拿来引用
在这里插入图片描述

假设左边是原图像的直方图,可以看到,直方图高的地方很高,而灰度值较低和较高的部分却没有像素,经过直方图均衡化(右图),图像像素的灰度值分配更加均匀,也就是说图像包含的像素灰度值更加丰富,对比度更高。这就是直方图均衡化的作用。

在这里插入图片描述

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
 
int main() {
	Mat srcImage, dstImage;
	srcImage = imread("2.jpg", 1);
	if (!srcImage.data) {
		printf("读取图片错误!\n");
		return false;
	}
 
	cvtColor(srcImage, srcImage, COLOR_BGR2GRAY);
	imshow("原始图", srcImage);
 
	//进行直方图均衡化
	equalizeHist(srcImage, dstImage);
 
	imshow("经过直方图均衡化后的图", dstImage);
 
	waitKey(0);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

发布了34 篇原创文章 · 获赞 8 · 访问量 1880

猜你喜欢

转载自blog.csdn.net/weixin_43583163/article/details/97646995
今日推荐