如何使用投影法在OpenCV中实现直线检测?

2026-05-08 17:213阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1393个文字,预计阅读时间需要6分钟。

如何使用投影法在OpenCV中实现直线检测?

本文以家庭分享为例,介绍了OpenCV检测直线之投影法的基本代码,供大家参考。以下是我对投影法的一点认识和实验:

投影法是数字图像处理中常用的方法,用于检测图像中的直线。其基本原理是将图像中的像素点按照一定的方向进行投影,然后统计投影结果,从而找到直线。

具体步骤如下:

如何使用投影法在OpenCV中实现直线检测?

1. 读取图像。

2.将图像转换为灰度图。

3.应用高斯模糊去除噪声。

4.使用Canny算子进行边缘检测。

5.对边缘图像进行霍夫变换,得到直线信息。

6.对直线进行投影,统计投影结果。

7.根据投影结果确定直线。

以下是实现投影法的Python代码示例:

python

import cv2import numpy as np

读取图像image=cv2.imread('image.jpg')

转换为灰度图gray=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

高斯模糊blurred=cv2.GaussianBlur(gray, (5, 5), 0)

Canny边缘检测edges=cv2.Canny(blurred, 50, 150)

霍夫变换检测直线lines=cv2.HoughLinesP(edges, 1, np.pi/180, threshold=100, minLineLength=100, maxLineGap=10)

投影for line in lines: x1, y1, x2, y2=line[0] dx=x2 - x1 dy=y2 - y1 proj=np.array([[-dy, dx], [0, 0], [dy, -dx]]) proj=proj / np.linalg.norm(proj, axis=0) proj=proj * 100 proj=proj.astype(int) for i in range(-50, 51): proj[0][0] +=i proj[0][1] +=i proj[1][0] +=i proj[1][1] +=i cv2.line(image, (proj[0][0], proj[0][1]), (proj[1][0], proj[1][1]), (0, 255, 0), 2)

显示结果cv2.imshow('Detected Lines', image)cv2.waitKey(0)cv2.destroyAllWindows()

以上代码实现了投影法检测直线的基本过程。通过调整参数,可以适应不同的图像和需求。

本文实例为大家分享了opencv检测直线之投影法的具体代码,供大家参考,具体内容如下

以下是我对投影法的一点认识和实验:

投影法就是数字图像在某个方向上进行像素累加。通过水平和垂直方向的投影,可以得到表格图像投影的几个特点:

(1)表格区域的水平与竖直投影分布通常出现周期性的尖峰

(2)在文字投影的行与行之间或列与列之间常会出现明显的空白区

因此,求图像水平以及竖直投影,根据特点分别设以阈值就可以将横线以及竖直线所在位置确定。

第一步:求图像的水平投影、竖直投影

第二步:设定合理阈值,求取大于阈值的坐标(水平投影记录纵坐标,垂直投影记录横坐标)

第三步:根据记录纵坐标恢复水平线,根据记录横坐标恢复竖直线。

下面附整体代码以及实验结果:

#include<iostream> #include<vector> #include <cv.h> #include <highgui.h> using namespace std; using namespace cv; Mat VerticalLine(Mat srcImageBin)//垂直线条检测 { vector <int> array;//动态数组用来存储投影值大于阈值的横坐标 int *colswidth = new int[srcImageBin.cols]; //申请src.image.cols个int型的内存空间,存储二值图中每列的白色像素数 memset(colswidth, 0, srcImageBin.cols * 4); //数组必须赋初值为零,否则出错。无法遍历数组。 int value; for (int i = 0; i < srcImageBin.cols; i++) { for (int j = 0; j < srcImageBin.rows; j++) { value = srcImageBin.at<uchar>(j, i); if (value == 255) { colswidth[i]++; //统计每列的白色像素点 } } } Mat lineImage(srcImageBin.rows, srcImageBin.cols, CV_8UC1, cv::Scalar(0, 0, 0)); //寻找投影大于阈值0.3*srcImageBin.rows的横坐标 for (int i = 0; i < srcImageBin.cols; i++) { bool flag = true; for (int j = 0; j < colswidth[i] && colswidth[i] >= (0.3*srcImageBin.rows); j++) { if (flag == true) { array.push_back(i); flag = false; } } } int count = array.size(); //恢复直线 for (int n = 0; n < srcImageBin.rows; n++) { for (int w = 0; w<count; w++) { if (srcImageBin.at<uchar>(n, array[w]) == 255) { lineImage.at<uchar>(n, array[w]) = 255; } } } delete[] colswidth; return lineImage; } Mat HorizonLine(Mat srcImageBin)//水平线条检测 { vector <int> array1; int *rowswidth = new int[srcImageBin.rows]; memset(rowswidth, 0, srcImageBin.rows * 4); int value; for (int i = 0; i < srcImageBin.rows; i++) { for (int j = 0; j < srcImageBin.cols; j++) { value = srcImageBin.at<uchar>(i, j); if (value == 255) { rowswidth[i]++; //统计每行的白色像素点 } } } Mat lineImage(srcImageBin.rows, srcImageBin.cols, CV_8UC1, cv::Scalar(0, 0, 0)); //寻找投影大于阈值0.525*srcImageBin.cols的纵坐标 for (int i = 0; i < srcImageBin.rows; i++) { bool flag = true; for (int j = 0; j < rowswidth[i] && rowswidth[i] >= (0.525*srcImageBin.cols); j++) { if (flag == true) { array1.push_back(i); flag = false; } } } int count = array1.size(); //恢复水平线 for (int h = 0; h<count; h++) { for (int m = 0; m < srcImageBin.cols; m++) { if (srcImageBin.at<uchar>(array1[h], m) == 255) { lineImage.at<uchar>(array1[h], m) = 255; } } } delete[] rowswidth;//释放前面申请的空间 return lineImage; } int main() { Mat srcImage = imread("E:\\x.jpg"); Mat closeimage; imshow("原图", srcImage); if (srcImage.channels() > 1) cvtColor(srcImage, srcImage, CV_RGB2GRAY); Mat srcImageBin; threshold(srcImage, srcImageBin, 140, 255, CV_THRESH_OTSU | CV_THRESH_BINARY_INV); Mat VP; VP = VerticalLine(srcImageBin); Mat HP; HP = HorizonLine(srcImageBin); Mat mergelineImage; bitwise_or(HP, VP, mergelineImage); imshow("mergelineImage", mergelineImage); waitKey(0); return 0; }

实验结果如下:

由上结果可知,如果直线中间有字会被误检为直线,图中用红色椭圆标出。

文中若有错误的不妥的地方,还望指出,以便共同学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。

本文共计1393个文字,预计阅读时间需要6分钟。

如何使用投影法在OpenCV中实现直线检测?

本文以家庭分享为例,介绍了OpenCV检测直线之投影法的基本代码,供大家参考。以下是我对投影法的一点认识和实验:

投影法是数字图像处理中常用的方法,用于检测图像中的直线。其基本原理是将图像中的像素点按照一定的方向进行投影,然后统计投影结果,从而找到直线。

具体步骤如下:

如何使用投影法在OpenCV中实现直线检测?

1. 读取图像。

2.将图像转换为灰度图。

3.应用高斯模糊去除噪声。

4.使用Canny算子进行边缘检测。

5.对边缘图像进行霍夫变换,得到直线信息。

6.对直线进行投影,统计投影结果。

7.根据投影结果确定直线。

以下是实现投影法的Python代码示例:

python

import cv2import numpy as np

读取图像image=cv2.imread('image.jpg')

转换为灰度图gray=cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

高斯模糊blurred=cv2.GaussianBlur(gray, (5, 5), 0)

Canny边缘检测edges=cv2.Canny(blurred, 50, 150)

霍夫变换检测直线lines=cv2.HoughLinesP(edges, 1, np.pi/180, threshold=100, minLineLength=100, maxLineGap=10)

投影for line in lines: x1, y1, x2, y2=line[0] dx=x2 - x1 dy=y2 - y1 proj=np.array([[-dy, dx], [0, 0], [dy, -dx]]) proj=proj / np.linalg.norm(proj, axis=0) proj=proj * 100 proj=proj.astype(int) for i in range(-50, 51): proj[0][0] +=i proj[0][1] +=i proj[1][0] +=i proj[1][1] +=i cv2.line(image, (proj[0][0], proj[0][1]), (proj[1][0], proj[1][1]), (0, 255, 0), 2)

显示结果cv2.imshow('Detected Lines', image)cv2.waitKey(0)cv2.destroyAllWindows()

以上代码实现了投影法检测直线的基本过程。通过调整参数,可以适应不同的图像和需求。

本文实例为大家分享了opencv检测直线之投影法的具体代码,供大家参考,具体内容如下

以下是我对投影法的一点认识和实验:

投影法就是数字图像在某个方向上进行像素累加。通过水平和垂直方向的投影,可以得到表格图像投影的几个特点:

(1)表格区域的水平与竖直投影分布通常出现周期性的尖峰

(2)在文字投影的行与行之间或列与列之间常会出现明显的空白区

因此,求图像水平以及竖直投影,根据特点分别设以阈值就可以将横线以及竖直线所在位置确定。

第一步:求图像的水平投影、竖直投影

第二步:设定合理阈值,求取大于阈值的坐标(水平投影记录纵坐标,垂直投影记录横坐标)

第三步:根据记录纵坐标恢复水平线,根据记录横坐标恢复竖直线。

下面附整体代码以及实验结果:

#include<iostream> #include<vector> #include <cv.h> #include <highgui.h> using namespace std; using namespace cv; Mat VerticalLine(Mat srcImageBin)//垂直线条检测 { vector <int> array;//动态数组用来存储投影值大于阈值的横坐标 int *colswidth = new int[srcImageBin.cols]; //申请src.image.cols个int型的内存空间,存储二值图中每列的白色像素数 memset(colswidth, 0, srcImageBin.cols * 4); //数组必须赋初值为零,否则出错。无法遍历数组。 int value; for (int i = 0; i < srcImageBin.cols; i++) { for (int j = 0; j < srcImageBin.rows; j++) { value = srcImageBin.at<uchar>(j, i); if (value == 255) { colswidth[i]++; //统计每列的白色像素点 } } } Mat lineImage(srcImageBin.rows, srcImageBin.cols, CV_8UC1, cv::Scalar(0, 0, 0)); //寻找投影大于阈值0.3*srcImageBin.rows的横坐标 for (int i = 0; i < srcImageBin.cols; i++) { bool flag = true; for (int j = 0; j < colswidth[i] && colswidth[i] >= (0.3*srcImageBin.rows); j++) { if (flag == true) { array.push_back(i); flag = false; } } } int count = array.size(); //恢复直线 for (int n = 0; n < srcImageBin.rows; n++) { for (int w = 0; w<count; w++) { if (srcImageBin.at<uchar>(n, array[w]) == 255) { lineImage.at<uchar>(n, array[w]) = 255; } } } delete[] colswidth; return lineImage; } Mat HorizonLine(Mat srcImageBin)//水平线条检测 { vector <int> array1; int *rowswidth = new int[srcImageBin.rows]; memset(rowswidth, 0, srcImageBin.rows * 4); int value; for (int i = 0; i < srcImageBin.rows; i++) { for (int j = 0; j < srcImageBin.cols; j++) { value = srcImageBin.at<uchar>(i, j); if (value == 255) { rowswidth[i]++; //统计每行的白色像素点 } } } Mat lineImage(srcImageBin.rows, srcImageBin.cols, CV_8UC1, cv::Scalar(0, 0, 0)); //寻找投影大于阈值0.525*srcImageBin.cols的纵坐标 for (int i = 0; i < srcImageBin.rows; i++) { bool flag = true; for (int j = 0; j < rowswidth[i] && rowswidth[i] >= (0.525*srcImageBin.cols); j++) { if (flag == true) { array1.push_back(i); flag = false; } } } int count = array1.size(); //恢复水平线 for (int h = 0; h<count; h++) { for (int m = 0; m < srcImageBin.cols; m++) { if (srcImageBin.at<uchar>(array1[h], m) == 255) { lineImage.at<uchar>(array1[h], m) = 255; } } } delete[] rowswidth;//释放前面申请的空间 return lineImage; } int main() { Mat srcImage = imread("E:\\x.jpg"); Mat closeimage; imshow("原图", srcImage); if (srcImage.channels() > 1) cvtColor(srcImage, srcImage, CV_RGB2GRAY); Mat srcImageBin; threshold(srcImage, srcImageBin, 140, 255, CV_THRESH_OTSU | CV_THRESH_BINARY_INV); Mat VP; VP = VerticalLine(srcImageBin); Mat HP; HP = HorizonLine(srcImageBin); Mat mergelineImage; bitwise_or(HP, VP, mergelineImage); imshow("mergelineImage", mergelineImage); waitKey(0); return 0; }

实验结果如下:

由上结果可知,如果直线中间有字会被误检为直线,图中用红色椭圆标出。

文中若有错误的不妥的地方,还望指出,以便共同学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。