文章目录
- 效果演示
- 二、直线检测
- 效果演示
思路方法:
- 通过边缘检测 + 轮廓发现或者直线检测最大外接矩形实现
- 通过二值分割 + 形态学方法 + Hough直线 ,然后再执行相应的处理
- 通过二值分割 + 形态学方法 + 直线拟合,求交点获取轮廓,仿射变换。
一、图像旋转与切边
头文件 image_feature_all.h
:声明类与公共函数
#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
class ImageFeature {
public:
void cut_edges(Mat& image);
void detect_line(Mat& image);
};
主函数main.cpp
调用该类的公共成员函数
#include "image_feature_all.h"
int main(int argc, char** argv) {
const char* img_path = "D:\\Desktop\\match_dst.jpg";
Mat image = imread(img_path);
if (image.empty()) {
cout << "图像数据为空,读取文件失败!" << endl;
}
ImageFeature imgfeature;
imgfeature.cut_edges(image);
imgfeature.detect_line(image);
waitKey(0);
destroyAllWindows();
return 0;
}
效果演示
源文件 feature_extract.cpp
:实现类与公共函数
static void on_thresh(int thresh, void* userdata) {
Mat image = *((Mat*)userdata);
int img_width = image.cols;
int img_height = image.rows;
Mat gray_src, edges;
cvtColor(image, gray_src, COLOR_BGR2GRAY);
Canny(gray_src, edges, thresh, 2 * thresh);
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(edges, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
//获取最小包围框的宽高
float max_w = 0;
float max_h = 0;
double degree = 0;
for (size_t i = 0; i < contours.size(); i++) {
RotatedRect rect_min = cv::minAreaRect(contours[i]);
if (abs(rect_min.angle) > 0) {
max_h = rect_min.size.height > max_h ? rect_min.size.height : max_h;
max_w = rect_min.size.width > max_w ? rect_min.size.width : max_w;
}
}
//绘制最小包围框的轮廓,可视化
RNG rng(12345);
Mat drawImg = Mat::zeros(gray_src.size(), CV_8UC3);
for (size_t i = 0; i < contours.size(); i++){
RotatedRect rect_min = cv::minAreaRect(contours[i]);
if (rect_min.size.height == max_h && rect_min.size.width == max_w) {
degree = rect_min.angle;
Point2f pts[4];
rect_min.points(pts);
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
for (size_t j = 0; j < 4; j++){
line(drawImg, pts[j], pts[(j + 1) % 4], color, 1, 8, 0);
}
}
}
cout << "[max_w,max_h,degree] = " << max_w<< " , " << max_h << " , " << degree << endl;
imshow("FindContours", drawImg);
// 旋正图像(同时旋转edges)
Mat dst;
Point2f center(image.rows / 2, image.cols / 2);
Mat rotate_mat = getRotationMatrix2D(center, -degree, 1);
warpAffine(image, dst, rotate_mat, image.size(), 1, 0, Scalar(255,255,255));
warpAffine(edges, edges, rotate_mat, image.size(), 1, 0);
imshow("dst", dst);
imshow("edges", edges);
// 旋转图像后切边(查找轮廓->筛选掉小框->切边)
vector<vector<Point>> contours_cut;
vector<Vec4i> hireachy_cut;
findContours(edges, contours_cut, hireachy_cut, RETR_TREE, CHAIN_APPROX_SIMPLE);
double minH = image.rows * 0.5;
double minW = image.cols * 0.5;
Mat goodImage = Mat::zeros(image.size(), CV_8UC3);
Rect box;
for (size_t i = 0; i < contours_cut.size(); i++){
RotatedRect min_rect = minAreaRect(contours_cut[i]);
if (min_rect.size.height > minH && min_rect.size.width ) {
Point2f pts[4];
min_rect.points(pts);
box = min_rect.boundingRect();
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
for (size_t j = 0; j < 4; j++){
line(goodImage, pts[j], pts[(j + 1) % 4], color, 1, 8, 0);
}
}
}
imshow("goodImage", goodImage);
if (box.width > 0 && box.height > 0 && box.width < img_width && box.height < img_height) {
Mat roiImg = dst(box);
imshow("roiImg", roiImg);
}
return;
}
void ImageFeature::cut_edges(Mat& image) {
namedWindow("FindContours", WINDOW_AUTOSIZE);
int thresh = 200;
int max_thresh = 400;
createTrackbar("thresh", "FindContours", &thresh, max_thresh, on_thresh, (void*)(&image));
on_thresh(thresh, &image);
}
形状复杂使用形态学预处理:
二、直线检测
思路:通过图像形态学操作来寻找直线,(提取表格 简单示例)霍夫获取位置信息与显示。
处理流程:
- 截取ROI区域
- 大津阈值二值化
- 形态学检测直线
- 腐蚀(加粗直线)
- 霍夫直线检测
- 可视化(筛选掉短直线)
void ImageFeature::detect_line(Mat& image) {
Mat roiImg, binaryImg, morphImg;
cvtColor(image, image, COLOR_BGR2GRAY);
Rect rect = Rect(10, 10, image.cols - 10, image.rows - 20);
roiImg = image(rect);
threshold(roiImg, binaryImg, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
imshow("binaryImg", binaryImg);
Mat kernel = cv::getStructuringElement(MORPH_RECT, Size(20, 1));
morphologyEx(binaryImg, morphImg, MORPH_OPEN, kernel);
kernel = cv::getStructuringElement(MORPH_RECT, Size(3, 3));
dilate(morphImg, morphImg, kernel);
imshow("morphImg", morphImg);
vector<Vec4i> lines;
HoughLinesP(morphImg, lines, 1, CV_PI / 180.0, 30, 20.0, 0);
Mat resultImg = roiImg.clone();
cvtColor(resultImg, resultImg, COLOR_GRAY2BGR);
for (size_t i = 0; i < lines.size(); i++){
Vec4i ln = lines[i];
cout << "x1,y1, x2,y2 = " << ln[0] << " , " <<ln[1] << "\t" << ln[2] << " , " << ln[3] << endl;
if ((ln[2] - ln[0]) > 80 && (ln[3] - ln[1]) < 2) {
line(resultImg, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 0, 255), 2, 8, 0);
}
}
imwrite("D:\\Desktop\\resultImg.png", resultImg);
imshow("resultImg", resultImg);
}
效果演示
关于检测直线并进行仿射变化