java hough_hough变换检测直线Java

hough变换检测直线原理:

假设在图像中存在一条直线y=k*x+b(此时k,b未知)。取直线上的任意两点进行说明,设为(x0,y0),(x1,y1)。

所有经过点(x0,y0)的直线满足:-x0*k+y0=b ---式1,那么以k、b为直角坐标轴做式1对应直线;

所有经过点(x1,y1)的直线满足:-x1*k+y1=b ---式2,那么以k、b为直角坐标轴做式2对应直线;

两直线交于一点(kk,bb),此时该交点对应的直线y=kk*x+bb就是(x0,y0),(x1,y1)所确定的直线。

在hough变换中,我们首先将直线方程转换为极坐标形式:x*cos(theta)+y*sin(theta)=r ---式3(theta,r未知)。同上述原理,假设已知直线上的点的坐标,那么经过该点的曲线方程就对应着hough变换空间(即theta,r坐标系)的一条曲线,同一条直线上的点必定在hough变换空间相交于一点(theta*,r*),该点就是待检测直线方程式3对应的theta、r。当然,在hough变换空间两条曲线相交确定的(theta,r)并不能足以说明我们检测到了一条直线,只有当在(theta,r)这一点累加的曲线个数很大,通常是超过了我们提前设定的某个阈值时,我们才认为在(theta,r)是对应有一条直线的,否则我们应该使用极大值抑制的方法将这些干扰点(theta,r)去掉。下图是copy过来的,大概看看就行。

51ad40448e62b038819f3c80c0ac6752.png

以下是hough变换检测直线的封装类,因实际需求,这里我是专门用来检测任意四边形的四条边的。

1 public classLineFilter {2 private intw;3 private inth;4 private inthalfX;5 private inthalfY;6 private intrmax;7 private intlineNum;8 private int[] output;9 private int[] n;10 private int[][] acc;11 private double[] sinValue;12 private double[] cosValue;13 private Listlist;14

15 //Acc累加器,同一个r,theta的点进行累加,累加个数为val

16 public classAcc {17 private int r = 0;18 private int theta = 0;19 private int val = 0;20 publicAcc() {21 }22 }23

24 public int[] lineDetect(int width, int height, int lineNumber, int[] input) {25 init(width, height, lineNumber);26 /*

27 * 转换:直角坐标空间~极坐标空间28 * 不断计算累加,最终得到相同(theta,r)的像素点累加个数acc[theta][r]29 **/

30 for (int theta = 0; theta < 180; theta++) {31 for (int x = 0; x < w; x++) {32 for (int y = 0; y < h; y++) {33 if (input[y * w + x] ==Color.BLACK) {34 int r = (int) ((x - halfX) * cosValue[theta] + (y - halfY) *sinValue[theta]);35 r = r + rmax;//r的原本取值范围为(-ramx,ramx),加rmax后取值范围为(0,2ramx)

36 if (r >= 0 && r < 2 *rmax)37 acc[theta][r]++;38 }39 }40 }41 }42 /*

43 * 很重要的一步:在3*3窗口内对累加值进行极大值抑制,保留窗口内累加值最大的(theta,r);44 * 之后将theta,r,acc[theta][r]添加进list里面;45 * 对list进行部分排序;46 * 之后取出list前面lineNum个Acc对象,通过theta和r值找出直角坐标空间的直线47 **/

48 rankList(acc);49 System.out.println(".........acc个数:" +list.size());50 n = new int[lineNum];51 for (int i = 0; i < lineNum; i++) {52 Acc acc =list.get(i);53 n[i] =drawLine(acc.r, acc.theta, n[i]);54 System.out.println("检测出的第" + i + "条直线点的累积个数:" + acc.r + "..." + acc.theta + "..." +acc.val);55 System.out.println("实际输出第" + i + "条直线点的个数:" +n[i]);56 }57 returnoutput;58 }59

60 private void init(int width, int height, intlineNumber) {61 w =width;62 h =height;63 halfX = w / 2;64 halfY = h / 2;65 lineNum =lineNumber;66 output = new int[w *h];67 int max =Math.max(w, h);68 rmax = (int) (Math.sqrt(2.0) *max);69 acc = new int[180][2 *rmax];70 list = new ArrayList<>();71 sinValue = new double[180];72 cosValue = new double[180];73 Arrays.fill(output, Color.WHITE);74 for (int theta = 0; theta < 180; theta++) {75 sinValue[theta] = Math.sin((theta * Math.PI) / 180);76 cosValue[theta] = Math.cos((theta * Math.PI) / 180);77 }78 }79

80 /*

81 * 排序Acc数组,只对前面几个Acc进行排序,找出lineSize个较大的Acc82 **/

83 private void rankList(int[][] acc) {84 /*

85 * 对(theta,r)进行极大值抑制,因为有时候因为计算误差或者直线不是很直的原因,86 * 同一条直线上的点转换到极坐标空间时,就会出现多对不同的(theta,r),多对不同的(theta,r)转换到直角坐标空间就出现了多条直线,87 * 这就是为什么原本图像中只有一条直线最后在该位置检测出了多条直线,因此在进行极坐标到直角坐标转换之前,88 * 有必要对(theta,r)进行极大值抑制,只保留累积值val最大的那一对(theta,r)89 **/

90 for (int theta = 0; theta < 180; theta++) {91 for (int r = 0; r < 2 * rmax; r++) {92 int val =acc[theta][r];93 boolean onlyLine = true;94 if (val > 0) {95 for (int tt = -1; tt <=1; tt++) {96 for (int rr = -1; rr <= 1; rr++) {97 int newtheta = theta +tt;98 int newr = r +rr;99 if (newtheta < 0 || newtheta >= 180)100 newtheta = 0;101 if (newr < 0 || newr >= 2 * rmax) newr = 0;102 if (acc[newtheta][newr] > val) onlyLine = false;103 }104 }105 /*

106 *在3*3窗口内累加值最大的(theta,r)我们才添加进list ,107 * 并标记theta,r,以及累加值val108 **/

109 if(onlyLine) {110 Acc subAcc = newAcc();111 subAcc.r = r -rmax;112 subAcc.theta =theta;113 subAcc.val =acc[theta][r];114 list.add(subAcc);115 }116 }117 }118 }119 /*

120 * 设置需要检测的直线条数为lineNum,121 * 按val值大小升序排列list,当然只需要进行前面部分的排序即可122 **/

123 for (int i = 0; i < lineNum; i++) {124 int max =i;125 for (int j = i + 1; j < list.size(); j++) {126 if (list.get(j).val >list.get(max).val) {127 max =j;128 }129 }130 if (max !=i) {131 Acc accmax =list.get(max);132 Acc acci =list.get(i);133 list.set(max, acci);134 list.set(i, accmax);135 }136 }137 }138

139 /*

140 *转换:极坐标空间~直角坐标空间141 *r=(x-halfx)*cos(theta)+(y-halfy)*sin(theta);142 * 已知r,theta,x或者y的情况下,通过该式计算出符合条件的y或者x。143 * 画出lineNum条直线144 **/

145 private int drawLine(int r, int theta, intn) {146 if (theta >= 45 && theta <= 135) {147 for (int x = 0; x < w; x++) {148 int y = (int) ((r - (x - halfX) * cosValue[theta]) / sinValue[theta]) +halfY;149 if (y >= 0 && y = 0 && x

166 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV提供了Hough变换函数`HoughLines`和`HoughLinesP`来实现图像中直线检测。 其中,`HoughLines`函数可以检测出所有直线,而`HoughLinesP`函数可以检测直线的端点坐标。 下面是一个简单的Java代码示例,用于实现对图像中直线检测: ```java import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.Point; import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.highgui.HighGui; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class HoughLines { public static void main(String[] args) { // 加载OpenCV库 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 读取图像 Mat src = Imgcodecs.imread("input.jpg"); // 转化为灰度图像 Mat gray = new Mat(); Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY); // 进行边缘检测 Mat edges = new Mat(); Imgproc.Canny(gray, edges, 50, 150, 3, false); // 进行Hough变换 Mat lines = new Mat(); Imgproc.HoughLines(edges, lines, 1, Math.PI / 180, 150); // 绘制直线 for (int i = 0; i < lines.rows(); i++) { double[] data = lines.get(i, 0); double rho = data[0]; double theta = data[1]; double a = Math.cos(theta); double b = Math.sin(theta); double x0 = a * rho; double y0 = b * rho; Point pt1 = new Point(Math.round(x0 + 1000 * (-b)), Math.round(y0 + 1000 * (a))); Point pt2 = new Point(Math.round(x0 - 1000 * (-b)), Math.round(y0 - 1000 * (a))); Imgproc.line(src, pt1, pt2, new Scalar(0, 0, 255), 3, Imgproc.LINE_AA, 0); } // 显示结果 HighGui.imshow("Hough Lines", src); HighGui.waitKey(); } } ``` 在这个示例中,我们首先使用`Imgproc.cvtColor`函数将图像转化为灰度图像,然后使用`Imgproc.Canny`函数进行边缘检测。接着,我们使用`Imgproc.HoughLines`函数进行Hough变换,得到所有直线的参数。最后,我们使用`Imgproc.line`函数在原图像上绘制直线。 注意:在使用Hough变换前,需要对图像进行边缘检测,因为Hough变换只能检测出边缘上的直线

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值