Java基于opencv—透视变换矫正图像
2021-06-17 10:03
标签:参考 roc index inter 获取 ref 灰度 接下来 string 很多时候我们拍摄的照片都会产生一点畸变的,就像下面的这张图 虽然不是很明显,但还是有一点畸变的,而我们要做的就是把它变成下面的这张图 效果看起来并不是很好,主要是四个顶点找的不准确,会有一些偏差,而且矫正后产生的目标图是倒着的,哪位好心人给说说为啥 因为我也没有测试畸变很大的图像,也不能保证方法适用于每个图像,这里仅提供我的思路供大家参考。 思路: 我们把思路再理一下: 1、寻找图像的四个顶点的坐标(重要) 我们来跟着思路实现一下代码 本项目所有代码地址:https://github.com/YLDarren/opencvHandleImg Java基于opencv—透视变换矫正图像 标签:参考 roc index inter 获取 ref 灰度 接下来 string 原文地址:https://www.cnblogs.com/qjmnong/p/9721395.html我们最重要的就是找到图像的四个顶点,有利用hough直线,求直线交点确定四个顶点,有采用寻找轮廓确定四个顶点等等;今天我提供的思路,也是采用寻找轮廓的方法,用approxPolyDP函数,对图像轮廓点进行多边形拟合,可以得到大概的一个这样的图
可以看到图像的四个顶点处,都有小白点。接下来我们要做的就是把这些点归类,即划分出四个区域[左上,右上,右下,左下];我采用的是利用opencv的寻找轮廓,得到最大轮廓,然后生成最小外接矩形,确定四个顶点的大致位置;然后设置一个阀值,与上图中的点集合求距离,大于阀值的舍弃,小于的保留,可以得到如下的图像
这样所有的点集都落到了四个区域,利用矩形中,对角线距离最大,确定四个顶点的位置,发现效果并不是很好,如下图
到此四个顶点的位置大概的确定了,就只需要根据输入和输出点获得图像透视变换的矩阵,然后透视变换;
思路: 1、canny描边 2、寻找最大轮廓 3、对最大轮廓点集合逼近,得到轮廓的大致点集合 4、把点击划分到四个区域中,即左上,右上,左下,右下 5、根据矩形中,对角线最长,找到矩形的四个顶点坐标
2、根据输入和输出点获得图像透视变换的矩阵
3、透视变换1、canny描边
/**
* canny算法,边缘检测
*
* @param src
* @return
*/
public static Mat canny(Mat src) {
Mat mat = src.clone();
Imgproc.Canny(src, mat, 60, 200);
HandleImgUtils.saveImg(mat, "C:/Users/admin/Desktop/opencv/open/x/canny.jpg");
return mat;
}
2、寻找最大轮廓;3、对最大轮廓点集合逼近,得到轮廓的大致点集合(代码中有很多冗余,后期会进行优化)
/**
* 利用函数approxPolyDP来对指定的点集进行逼近 精确度设置好,效果还是比较好的
*
* @param cannyMat
*/
public static Point[] useApproxPolyDPFindPoints(Mat cannyMat) {
List
获取四个顶点的参照点
/**
* 获取四个顶点的参照点,返回Point数组[左上,右上,右下,左下] 思路: 我们可以把四个点分成两部分,左部分,右部分
* 左部分:高的为左上,低的为左下(高低是以人的视觉) 右部分同理 首先我们找到最左和最右的位置,以它们的两个中间为分界点,
* 靠左的划分到左部分,靠右的划分到右部分 如果一个区域有三个或更多,哪个比较靠近分界线,划分到少的那个区域
*
* @param cannyMat
* @return
*/
public static Point[] findReferencePoint(Mat cannyMat) {
RotatedRect rect = findMaxRect(cannyMat);
Point[] referencePoints = new Point[4];
rect.points(referencePoints);
double minX = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
for (int i = 0; i maxX ? referencePoints[i].x : maxX;
}
double center = (minX + maxX) / 2;
List
4、把点击划分到四个区域中,即左上,右上,右下,左下(效果还可以)
/**
* 把点击划分到四个区域中,即左上,右上,右下,左下
*
* @param points
* 逼近的点集
* @param referencePoints
* 四个参照点集(通过寻找最大轮廓,进行minAreaRect得到四个点[左上,右上,右下,左下])
*/
public static Map
5、根据矩形中,对角线最长,找到矩形的四个顶点坐标(效果不好)
/**
* 具体的寻找四个顶点的坐标
*
* @param map
* 四个点集域 即左上,右上,右下,左下
* @return
*/
public static Point[] specificFindFourPoint(Map
整合寻找四个顶点坐标函数
/**
* 寻找四个顶点的坐标 思路: 1、canny描边 2、寻找最大轮廓 3、对最大轮廓点集合逼近,得到轮廓的大致点集合
* 4、把点击划分到四个区域中,即左上,右上,左下,右下 5、根据矩形中,对角线最长,找到矩形的四个顶点坐标
*
* @param src
*/
public static Point[] findFourPoint(Mat src) {
// 1、canny描边
Mat cannyMat = canny(src);
// 2、寻找最大轮廓;3、对最大轮廓点集合逼近,得到轮廓的大致点集合
Point[] points = useApproxPolyDPFindPoints(cannyMat);
//在图像上画出逼近的点
Mat approxPolyMat = src.clone();
for( int i = 0; i map = pointsDivideArea(points, referencePoints);
// 画出标记四个区域中的点集
Mat areaMat = src.clone();
List
透视变换,矫正图像
/**
* 透视变换,矫正图像 思路: 1、寻找图像的四个顶点的坐标(重要) 思路: 1、canny描边 2、寻找最大轮廓
* 3、对最大轮廓点集合逼近,得到轮廓的大致点集合 4、把点击划分到四个区域中,即左上,右上,左下,右下 5、根据矩形中,对角线最长,找到矩形的四个顶点坐标
* 2、根据输入和输出点获得图像透视变换的矩阵 3、透视变换
*
* @param src
*/
public static Mat warpPerspective(Mat src) {
// 灰度话
src = HandleImgUtils.gray(src);
// 找到四个点
Point[] points = HandleImgUtils.findFourPoint(src);
// Canny
Mat cannyMat = HandleImgUtils.canny(src);
// 寻找最大矩形
RotatedRect rect = HandleImgUtils.findMaxRect(cannyMat);
// 点的顺序[左上 ,右上 ,右下 ,左下]
List
测试函数
/**
* 测试透视变换
*/
public void testWarpPerspective() {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat src = HandleImgUtils.matFactory("C:/Users/admin/Desktop/opencv/open/q/x10.jpg");
src = HandleImgUtils.warpPerspective(src);
HandleImgUtils.saveImg(src, "C:/Users/admin/Desktop/opencv/open/q/x10-testWarpPerspective.jpg");
}
觉得写的不错话,还是希望能给个Star的