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!
The Hough Transform is a method that is used in image processing to detect any shape, if that shape can be represented in mathematical form. It can detect the shape even if it is broken or distorted a little bit.
Use the HoughLinesP() Function of OpenCV to Detect Lines in an Image in Python. The HoughLinesP() function uses probabilistic Hough line transform to detect lines. We have to read the given image using the imread() function, convert it into grayscale, and then find its edges using Canny() .
In image processing, line detection is an algorithm that takes a collection of n edge points and finds all the lines on which these edge points lie. The most popular line detectors are the Hough transform and convolution-based techniques.
Thus, the Hough Transform algorithm detects lines by finding the (ρ, θ) pairs that have a number of intersections larger than a certain threshold.
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 :
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 :
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With