Java基于opencv—矫正图像

时间:2023-02-09 12:24:33

更多的时候,我们得到的图像不可能是正的,多少都会有一定的倾斜,就比如下面的

Java基于opencv—矫正图像

我们要做的就是把它们变成下面这样的

Java基于opencv—矫正图像

我们采用的是寻找轮廓的思路,来矫正图片;只要有明显的轮廓都可以采用这种思路

具体思路:

1、先用opencv提供的canny函数,进行一次边缘检测

2、再用opencv提供的findContours函数,寻找图像的轮廓,从中间结果种,找到最大的轮廓,就是我们图像的最外面的轮廓

3、得到最终轮廓后,计算矩形轮廓与水平的夹角,然后旋转图像

4、最后我们在从旋转后的图像中,把我们感兴趣的切割出来,就可以了

我们实际的实现一下

先用opencv提供的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;
}

再用opencv提供的findContours函数,寻找图像的轮廓,从中间结果种,找到最大的轮廓,就是我们图像的最外面的轮廓

/**
* 返回边缘检测之后的最大矩形,并返回
*
* @param cannyMat
* Canny之后的mat矩阵
* @return
*/
public static RotatedRect findMaxRect(Mat cannyMat) { List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat(); // 寻找轮廓
Imgproc.findContours(cannyMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE,
new Point(0, 0)); // 找出匹配到的最大轮廓
double area = Imgproc.boundingRect(contours.get(0)).area();
int index = 0; // 找出匹配到的最大轮廓
for (int i = 0; i < contours.size(); i++) {
double tempArea = Imgproc.boundingRect(contours.get(i)).area();
if (tempArea > area) {
area = tempArea;
index = i;
}
} MatOfPoint2f matOfPoint2f = new MatOfPoint2f(contours.get(index).toArray()); RotatedRect rect = Imgproc.minAreaRect(matOfPoint2f); return rect;
}

得到最终轮廓后,计算矩形轮廓与水平的夹角,然后旋转图像

/**
* 旋转矩形
*
* @param src
* mat矩阵
* @param rect
* 矩形
* @return
*/
public static Mat rotation(Mat cannyMat, RotatedRect rect) {
// 获取矩形的四个顶点
Point[] rectPoint = new Point[4];
rect.points(rectPoint); double angle = rect.angle + 90; Point center = rect.center; Mat CorrectImg = new Mat(cannyMat.size(), cannyMat.type()); cannyMat.copyTo(CorrectImg); // 得到旋转矩阵算子
Mat matrix = Imgproc.getRotationMatrix2D(center, angle, 0.8); Imgproc.warpAffine(CorrectImg, CorrectImg, matrix, CorrectImg.size(), 1, 0, new Scalar(0, 0, 0)); return CorrectImg;
}

最后我们在从旋转后的图像中,把我们感兴趣的切割出来,就可以了

/**
* 把矫正后的图像切割出来
*
* @param correctMat
* 图像矫正后的Mat矩阵
*/
public static void cutRect(Mat correctMat , Mat nativeCorrectMat) {
// 获取最大矩形
RotatedRect rect = findMaxRect(correctMat); Point[] rectPoint = new Point[4];
rect.points(rectPoint); int startLeft = (int)Math.abs(rectPoint[0].x);
int startUp = (int)Math.abs(rectPoint[0].y < rectPoint[1].y ? rectPoint[0].y : rectPoint[1].y);
int width = (int)Math.abs(rectPoint[2].x - rectPoint[0].x);
int height = (int)Math.abs(rectPoint[1].y - rectPoint[0].y); System.out.println("startLeft = " + startLeft);
System.out.println("startUp = " + startUp);
System.out.println("width = " + width);
System.out.println("height = " + height); for(Point p : rectPoint) {
System.out.println(p.x + " , " + p.y);
} Mat temp = new Mat(nativeCorrectMat , new Rect(startLeft , startUp , width , height ));
Mat t = new Mat();
temp.copyTo(t); HandleImgUtils.saveImg(t , "C:/Users/admin/Desktop/opencv/open/x/cutRect.jpg");
}

整合整个过程

/**
* 矫正图像
*
* @param src
* @return
*/
public static void correct(Mat src) {
// Canny
Mat cannyMat = canny(src); // 获取最大矩形
RotatedRect rect = findMaxRect(cannyMat); // 旋转矩形
Mat CorrectImg = rotation(cannyMat , rect);
Mat NativeCorrectImg = rotation(src , rect); //裁剪矩形
cutRect(CorrectImg , NativeCorrectImg); HandleImgUtils.saveImg(src, "C:/Users/admin/Desktop/opencv/open/x/srcImg.jpg"); HandleImgUtils.saveImg(CorrectImg, "C:/Users/admin/Desktop/opencv/open/x/correct.jpg");
}

测试代码

/**
* 测试矫正图像
*/
public void testCorrect() {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat src = HandleImgUtils.matFactory("C:/Users/admin/Desktop/opencv/open/x/x7.jpg");
HandleImgUtils.correct(src);
}

Java方面opencv的例子还是蛮少的,代码都是自己参考博客写的,照顾不周的地方,请见谅

本项目的所有代码地址:https://github.com/YLDarren/opencvHandleImg

Java基于opencv—矫正图像的更多相关文章

  1. Java基于opencv实现图像数字识别&lpar;五&rpar;—投影法分割字符

    Java基于opencv实现图像数字识别(五)-投影法分割字符 水平投影法 1.水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像): 2.选出一个最优的阀值,根据比这个阀值大或小 ...

  2. Java基于opencv实现图像数字识别&lpar;四&rpar;—图像降噪

    Java基于opencv实现图像数字识别(四)-图像降噪 我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类 这个工具类呢,就一个成员变量 ...

  3. Java基于opencv实现图像数字识别&lpar;三&rpar;—灰度化和二值化

    Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...

  4. Java基于opencv实现图像数字识别&lpar;二&rpar;—基本流程

    Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要 ...

  5. Java基于opencv实现图像数字识别&lpar;一&rpar;

    Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用Buffere ...

  6. Java基于opencv实现图像数字识别&lpar;五&rpar;—腐蚀、膨胀处理

    腐蚀:去除图像表面像素,将图像逐步缩小,以达到消去点状图像的效果:作用就是将图像边缘的毛刺剔除掉 膨胀:将图像表面不断扩散以达到去除小孔的效果:作用就是将目标的边缘或者是内部的坑填掉 使用相同次数的腐 ...

  7. Java基于OpenCV实现走迷宫(图片&plus;路线展示)

    Java基于OpenCV实现走迷宫(图片+路线展示) 由于疫情,待在家中,太过无聊.同学发了我张迷宫图片,让我走迷宫来缓解暴躁,于是乎就码了一个程序出来.特此记录. 原图: 这张图,由于不是非常清晰, ...

  8. Java基于opencv—透视变换矫正图像

    很多时候我们拍摄的照片都会产生一点畸变的,就像下面的这张图 虽然不是很明显,但还是有一点畸变的,而我们要做的就是把它变成下面的这张图 效果看起来并不是很好,主要是四个顶点找的不准确,会有一些偏差,而且 ...

  9. 为基于OpenCV的图像处理程序编写界面—关于QT&bsol;MFC&bsol;CSharp的选择以及GOCW的介绍

            基于OpenCV编写图像处理项目,除了算法以外,比较重要一个问题就是界面设计问题.对于c++语系的程序员来说,一般来说有QT/MFC两种考虑.QT的确功能强大,特别是QML编写andr ...

随机推荐

  1. 修复 Windows7 资源管理器左侧收藏夹无法展开问题

    相信大家在网上搜多到的解决办法大多数都是修改注册表,但是这个办法多数是无效的 1.运行regedit 2.展开到HKEY_CLASSES_ROOT\lnkfile 3.添加一个字符串值:IsShort ...

  2. 使用MapReduce实现一些经典的案例

    在工作中,很多时候都是用hive或pig来自动化执行mr统计,但是我们不能忘记原始的mr.本文记录了一些通过mr来完成的经典的案例,有倒排索引.数据去重等,需要掌握. 一.使用mapreduce实现倒 ...

  3. Spring依赖注入 --- 简单使用说明

    Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ...

  4. EBP的妙用&lbrack;无法使用ESP定律时&rsqb;

    1.了解EBP寄存器 在寄存器里面有很多寄存器虽然他们的功能和使用没有任何的区别,但是在长期的编程和使用 中,在程序员习惯中已经默认的给每个寄存器赋上了特殊的含义,比如:EAX一般用来做返回值,ECX ...

  5. PostgreSQL中,如何查表属于哪个数据库

    db1=# \x Expanded display is on. db1=# SELECT * FROM information_schema.tables WHERE table_name='tab ...

  6. Android游戏快速入门(一):基础储备

    智能手机时代已经到来了,手机的性能正在以你我惊讶的速度提升.那么手机游戏也在迅速发展,从简单的平面单机游戏不断的向复杂的3D网络游戏发展.所以,手机游戏的市场肯定也在不断扩张.那么,作为程序猿,我们也 ...

  7. easyui 1&period;3&period;3 中combotree post传参问题

    重写Tree的loader,增加queryParams属性支持,并且增加setQueryParams方法 //重写tree的loader $.extend($.fn.tree.defaults, { ...

  8. arclistsg独立单表模型文档列表

    arclistsg独立单表模型文档列表 (DedeCMS > 5.3) 名称:arclistsg 功能:类似arclist标签,获取指定单表模型(例如:分类信息),指定栏目,指定排序及呈现样式的 ...

  9. ASP&period;NET中登录时记住用户名和密码(附源码下载)--ASP&period;NET

    必需了解的:实例需要做的是Cookie对象的创建和对Cookie对象数据的读取,通过Response对象的Cookies属性创建Cookie,通过Request对象的Cookies可以读取Cookie ...

  10. ACM Adding Reversed Numbers(summer2017)

    The Antique Comedians of Malidinesia prefer comedies to tragedies. Unfortunately, most of the ancien ...