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—矫正图像的更多相关文章
- Java基于opencv实现图像数字识别(五)—投影法分割字符
Java基于opencv实现图像数字识别(五)-投影法分割字符 水平投影法 1.水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像): 2.选出一个最优的阀值,根据比这个阀值大或小 ...
- Java基于opencv实现图像数字识别(四)—图像降噪
Java基于opencv实现图像数字识别(四)-图像降噪 我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类 这个工具类呢,就一个成员变量 ...
- Java基于opencv实现图像数字识别(三)—灰度化和二值化
Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...
- Java基于opencv实现图像数字识别(二)—基本流程
Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要 ...
- Java基于opencv实现图像数字识别(一)
Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用Buffere ...
- Java基于opencv实现图像数字识别(五)—腐蚀、膨胀处理
腐蚀:去除图像表面像素,将图像逐步缩小,以达到消去点状图像的效果:作用就是将图像边缘的毛刺剔除掉 膨胀:将图像表面不断扩散以达到去除小孔的效果:作用就是将目标的边缘或者是内部的坑填掉 使用相同次数的腐 ...
- Java基于OpenCV实现走迷宫(图片+路线展示)
Java基于OpenCV实现走迷宫(图片+路线展示) 由于疫情,待在家中,太过无聊.同学发了我张迷宫图片,让我走迷宫来缓解暴躁,于是乎就码了一个程序出来.特此记录. 原图: 这张图,由于不是非常清晰, ...
- Java基于opencv—透视变换矫正图像
很多时候我们拍摄的照片都会产生一点畸变的,就像下面的这张图 虽然不是很明显,但还是有一点畸变的,而我们要做的就是把它变成下面的这张图 效果看起来并不是很好,主要是四个顶点找的不准确,会有一些偏差,而且 ...
- 为基于OpenCV的图像处理程序编写界面—关于QT\MFC\CSharp的选择以及GOCW的介绍
基于OpenCV编写图像处理项目,除了算法以外,比较重要一个问题就是界面设计问题.对于c++语系的程序员来说,一般来说有QT/MFC两种考虑.QT的确功能强大,特别是QML编写andr ...
随机推荐
- linux图像界面连接-xdm
有两种方法可以激活 --:修改/etc/gdm/custom.conf文件在 [security]字段下增加AllowRemoteRoot=true [xdmcp]字段下增加Enable=true - ...
- 为虚机Linux系统设置静态IP,ping通外网并解决相关问题
在虚机中安装完Linux系统后,虚机是ping不通外网的,而默认的动态IP会为之后的Hadoop应用造成不少麻烦,为了减少这些不必要的麻烦,我们把系统的IP设置为静态. 步骤: 修改系统配置文件 命令 ...
- Winsock API编程介绍
相信很多人都对网络编程感兴趣,下面我们就来介绍,在网络编程中应用最广泛的编程接口Winsock API. 使用Winsock API的编程,应该了解一些TCP/IP的基础知识.虽然你可以直接使用Win ...
- THUWC2019游记
Day -INF 听说自己苟进了THUWC,然而我还什么都不会啊,这样去了不得被吊打. 随便列了几个WC前的计划,然而到最后一个都没有完成,感觉学习效率好低啊,周围一众神仙天天吊打我. Day 0 坐 ...
- 通读SCRUM实战指南教材,提出5个问题。
问题一:为什么要制定优先级的排定和调整? 创建一个排好优先级的项目组合并讲重点放在转移团队上,如果做得对,可以消除在项目数量超过团队能力 的情况下过于常见的多任务处理. 问题二:为什么我们要做文档? ...
- 决策树(ID3、C4.5、CART)
ID3决策树 ID3决策树分类的根据是样本集分类前后的信息增益. 假设我们有一个样本集,里面每个样本都有自己的分类结果. 而信息熵可以理解为:“样本集中分类结果的平均不确定性”,俗称信息的纯度. 即熵 ...
- 用Tensorflow搭建神经网络的一般步骤
用Tensorflow搭建神经网络的一般步骤如下: ① 导入模块 ② 创建模型变量和占位符 ③ 建立模型 ④ 定义loss函数 ⑤ 定义优化器(optimizer), 使 loss 达到最小 ⑥ 引入 ...
- [Oracle][DATAGUARD] 关于确认PHYSICAL STANDBY的同期状况的方法
补上简单的确认PHYSICAL STANDBY的同期状况的方法: ODM TEST CASE===================Name = TC#1010_3 ####Primary#### SQ ...
- leetcode python 041首个缺失正数
##限定时间复杂度O(n)num=[0,5,3,1,2,-2,4,8,5,6]num=set(num)d=1for i in range(1,len(num)+1): if d in num: ...
- DAY1 练习
要求:⽤户登陆(三次输错机会)且每次输错误时显示剩余错误次数(提示:使⽤字符串格式化), 如果三次用完了之后 问是否再试试 再给三次机会 如果不想试了说没有机会了. list = [{'usernam ...