Java调用opencv图片矫正

1,706 阅读2分钟

1.通过霍夫线矫正土图片

image.png

public static void getCorrect1(Mat image) {
Mat clone=image.clone();
Mat src=image.clone();

int width = image.width();
int height = image.height();
int pointCount = width * height;
Mat points=image.reshape(3, pointCount);
points.convertTo(points,  CvType.CV_32F);

Imgproc.GaussianBlur(clone, clone, new Size(3, 3), 0, 0);
HighGui.imshow("GaussianBlur", clone);

Imgproc.cvtColor(clone, clone,Imgproc.COLOR_BGR2GRAY);
HighGui.imshow("GRY", clone);
//一般来说,高阈值maxVal推荐是低阈值minVal的2~3倍
int lowThresh=20;
//边缘检测
Imgproc.Canny(clone, clone,lowThresh, lowThresh*3,3);
HighGui.imshow("Canny", clone);

Mat storage = new Mat();
/**
	 * HoughLines(Mat image, Mat lines, double rho, double theta, int threshold, double srn, double stn, double min_theta, double max_theta)
	 * image 原图
	 * lines 霍夫线变换检测到线条的输出矢量,由(ρ,θ)表示
	 * rho   以像素为单位的距离精度(直线搜索时的进步尺寸的单位半径)
	 * theta 以弧度为单位的角度精度(直线搜索时的进步尺寸的角度单位)
	 * threshold 累加平面的阈值参数(直线被识别时它在累加平面中必须达到的值)
	 * srn    对于多尺度霍夫变换,这是第三个参数进步尺寸的除数距离。
        *        粗略累加器进步尺寸直接是rho,精确的累加器进步尺寸为rho/srn
	 * min_theta 检测到的直线的最小角度
	 * max_theta 测到的直线的最大角度
	 */
double sum = 0;
double angle=0;
Imgproc.HoughLines(clone, storage, 1, Math.PI/ 180.0, 200, 0, 0);
for (int x = 0; x < storage.rows(); x++) {
	double[] vec = storage.get(x, 0);

	double rho = vec[0];
	double theta = vec[1];

	Point pt1 = new Point();
	Point pt2 = new Point();

	double a = Math.cos(theta);
	double b = Math.sin(theta);

	double x0 = a * rho;
	double y0 = b * rho;

	pt1.x = Math.round(x0 + 1000 * (-b));
	pt1.y = Math.round(y0 + 1000 * (a));
	pt2.x = Math.round(x0 - 1000 * (-b));
	pt2.y = Math.round(y0 - 1000 * (a));
	sum += theta;
	Imgproc.line(clone, pt1, pt2, new Scalar(255, 255, 255, 255), 1, Imgproc.LINE_4, 0);
}

HighGui.imshow("houghLines", clone);

double average = sum / storage.rows(); //对所有角度求平均,这样做旋转效果会更好
angle = average/ Math.PI * 180 - 90;
System.out.println("average:"+angle);
Point center=new Point();
center.x=image.cols()/2;
center.y=image.rows()/2;

// 得到旋转矩阵算子
Mat matrix = Imgproc.getRotationMatrix2D(center, angle, 1);
Imgproc.warpAffine(src, src, matrix,src.size(), 1, 0, new Scalar(0, 0, 0));

HighGui.imshow("rotation", src);
}

2.通过轮廓检测矫正土图片

image.png

public static Mat getCorrect2(Mat image) {
Mat clone=image.clone();
Mat src=image.clone();

int width = image.width();
int height = image.height();
int pointCount = width * height;
Mat points=image.reshape(3, pointCount);
points.convertTo(points,  CvType.CV_32F);

Imgproc.GaussianBlur(clone, clone, new Size(3, 3), 0, 0);
HighGui.imshow("GaussianBlur", clone);

Imgproc.cvtColor(clone, clone,Imgproc.COLOR_BGR2GRAY);
HighGui.imshow("GRY", clone);

List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Mat hierarchy = new Mat();

// 寻找轮廓
Imgproc.findContours(clone, 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);
    
 // 获取矩形的四个顶点
Point[] rectpoint = new Point[4];
rect.points(rectpoint);

double line1 = Math.sqrt((rectpoint[1].y - rectpoint[0].y)*(rectpoint[1].y - rectpoint[0].y) + (rectpoint[1].x - rectpoint[0].x)*(rectpoint[1].x - rectpoint[0].x));
double line2 = Math.sqrt((rectpoint[3].y - rectpoint[0].y)*(rectpoint[3].y - rectpoint[0].y) + (rectpoint[3].x - rectpoint[0].x)*(rectpoint[3].x - rectpoint[0].x));

double angle = rect.angle;

if (line1 > line2) 
{
	angle = 90 + angle;
}

Point center = rect.center;
Mat CorrectImg = new Mat(clone.size(), clone.type());
clone.copyTo(CorrectImg);
// 得到旋转矩阵算子
Mat matrix = Imgproc.getRotationMatrix2D(center, angle, 0.8);
Imgproc.warpAffine(src, src, matrix, CorrectImg.size(), 1, 0, new Scalar(0, 0, 0));

HighGui.imshow("rotation", src);
return src;
}

3.两个算法的应用场景

基于轮廓提取的矫正算法更适用于车牌、身份证、人民币、书本、发票一类矩形形状而且边界明显的物体矫正。

基于直线探测的矫正算法更适用于文本类的矫正。

参考

www.jianshu.com/p/9eb9d6f6f… www.cnblogs.com/skyfsm/p/69…