15

I have the image below. I want to detect the line that divides this object in two pieces. Which is the best way? I've tried with the Hough transform but sometimes the object is not big enough for it to detect. Any ideias?

Thanks!

enter image description here

Luis Carlos
  • 333
  • 2
  • 6
  • 18

1 Answers1

41

Normally, Hough Transform is used for line detection.

But if it doesn't work for you, fitting line is also a good alternative.

Check OpenCV fitline function for more details and parameters.

Since you have already tried hough lines, I will demonstrate fitting line here, using OpenCV-Python :

# Load image, convert to grayscale, threshold and find contours
img = cv2.imread('lail.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hier = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]

# then apply fitline() function
[vx,vy,x,y] = cv2.fitLine(cnt,cv2.cv.CV_DIST_L2,0,0.01,0.01)

# Now find two extreme points on the line to draw line
lefty = int((-x*vy/vx) + y)
righty = int(((gray.shape[1]-x)*vy/vx)+y)

#Finally draw the line
cv2.line(img,(gray.shape[1]-1,righty),(0,lefty),255,2)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Below is the result I got :

enter image description here

enter image description here

EDIT :

If you want to find the line to divide the object into two pieces, first find the fitting line, then find the line normal to it.

For that, add below piece of code under cv2.fitLine() function :

nx,ny = 1,-vx/vy
mag = np.sqrt((1+ny**2))
vx,vy = nx/mag,ny/mag

And below are the results I got :

enter image description here

enter image description here

Hope it helps !!!

UPDATE :

Below is the C++ code for Python code of first case as you requested. The code works fine for me. Output is same as given above :

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv/cv.h>

using namespace std;
using namespace cv;

int main()
{
    cv::Mat img, gray,thresh;
    vector<vector<Point>> contours;
    Vec4f lines;

    img = cv::imread("line.png");
    cv::cvtColor(img,gray,cv::COLOR_BGR2GRAY);
    cv::threshold(gray,thresh,127,255,cv::THRESH_BINARY);
    cv::findContours(thresh,contours,cv::RETR_LIST,cv::CHAIN_APPROX_SIMPLE);
    cv::fitLine(Mat(contours[0]),lines,2,0,0.01,0.01);

    //lefty = int((-x*vy/vx) + y)
    //righty = int(((gray.shape[1]-x)*vy/vx)+y)
    int lefty = (-lines[2]*lines[1]/lines[0])+lines[3];
    int righty = ((gray.cols-lines[2])*lines[1]/lines[0])+lines[3];

    cv::line(img,Point(gray.cols-1,righty),Point(0,lefty),Scalar(255,0,0),2);

    cv::imshow("img",img);
    cv::waitKey(0);
    cv::destroyAllWindows();
}
Abid Rahman K
  • 51,886
  • 31
  • 146
  • 157
  • 1
    Thank you very much, i will try this today :D Oh, i am a fan of your blog :) – Luis Carlos Jan 07 '13 at 19:51
  • Do you have any version for C++? :P – Luis Carlos Jan 07 '13 at 21:25
  • 1
    Hi, all the functions are standard functions from OpenCV. So if you check the opencv docs, you can find corresponding C++ functions for every python function I used. Please try it yourself, and if you find any difficulty, comment me. I will try to help... – Abid Rahman K Jan 08 '13 at 06:50
  • 1
    +1 - Thank you, It is good to know you benefit from my blog. Keep visiting, and share it if you like. – Abid Rahman K Jan 08 '13 at 06:51
  • I already tried, with no luck :( The program exit automatically with no error. Actualy its in Java i want to do, but a version in c++ is just fine. – Luis Carlos Jan 08 '13 at 14:11
  • Here is my code in JAVA: `CvSeq lines; CvPoint[] pt=new CvPoint[2]; float 0,linee[] = new float[4],t; CvSeq cvSeq=new CvSeq(); //After CVT to gray and Threshold cvFindContours(opencv.BufferGray,storage,cvSeq, Loader.sizeof(CvContour.class),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE); cvFitLine(cvSeq,CV_DIST_L2,0,0.01,0.01,linee); float d = (float) Math.sqrt((double)linee[0]*linee[0] + (double)linee[1]*linee[1]); linee[0]/=d; linee[1]/=d;` – Luis Carlos Jan 08 '13 at 14:16
  • `t = (float)(largura + altura); pt[0].x(Math.round(linee[2] - linee[0]*t)); pt[0].y(Math.round(linee[3] - linee[1]*t)); pt[1].x(Math.round(linee[2] + linee[0]*t)); pt[1].y(Math.round(linee[3] + linee[1]*t)); cvLine( opencv.Buffer, pt[0], pt[1], CV_RGB(0,255,0), 3, CV_AA, 0 ); ` – Luis Carlos Jan 08 '13 at 14:16
  • 2
    Sorry for so long time. I did it, thanks :) Check my latest project: http://www.youtube.com/watch?v=zXHXusO8eGw – Luis Carlos Mar 08 '13 at 17:18
  • This really helped me too! Thanks – Ivantha Aug 16 '16 at 06:22