Abhyudai
Abhyudai

Reputation: 924

Detect the green lines in this image and calculate their lengths

enter image description hereSample Images

The image can be more noisy at times where more objects intervene from the background. Right now I am using various techniques using the RGB colour space to detect the lines but it fails when there is change in the colour due to intervening obstacles from the background. I am using opencv and python. I have read that HSV is better for colour detection and used but haven't been successful yet. I am not able to find a generic solution to this problem. Any hints or clues in this direction would be of great help.

Upvotes: 3

Views: 2714

Answers (2)

Amitay Nachmani
Amitay Nachmani

Reputation: 3279

You should use the fact that you know you are trying to detect a line by using the line hough transform. http://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html

  • When the obstacle also look like a line use the fact that you know approximately what is the orientation of the green lines.
  • If you don't know the orientation of the line use hte fact that there are several green lines with the same orientation and only one line that is the obstacle

Here is a code for what i meant:

import cv2
import numpy as np

# Params
minLineCount = 300 # min number of point alogn line with the a specif orientation
minArea = 100

# Read img
img = cv2.imread('i.png')
greenChannel = img[:,:,1]

# Do noise reduction
iFilter = cv2.bilateralFilter(greenChannel,5,5,5)

# Threshold data
#ret,iThresh = cv2.threshold(iFilter,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
iThresh = (greenChannel > 4).astype(np.uint8)*255

# Remove small areas
se1 = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
iThreshRemove = cv2.morphologyEx(iThresh, cv2.MORPH_OPEN, se1)

# Find edges
iEdge = cv2.Canny(iThreshRemove,50,100)

# Hough line transform
lines = cv2.HoughLines(iEdge, 1, 3.14/180,75)

# Find the theta with the most lines
thetaCounter = dict()
for line in lines:
    theta = line[0, 1]
    if theta in thetaCounter:
        thetaCounter[theta] += 1
    else:
        thetaCounter[theta] = 1

maxThetaCount = 0
maxTheta = 0
for theta in thetaCounter:
    if thetaCounter[theta] > maxThetaCount:
        maxThetaCount = thetaCounter[theta]
        maxTheta = theta

# Find the rhos that corresponds to max theta
rhoValues = []
for line in lines:
    rho = line[0, 0]
    theta = line[0, 1]
    if theta == maxTheta:
        rhoValues.append(rho)

# Go over all the lines with the specific orientation and count the number of pixels on that line
# if the number is bigger than minLineCount draw the pixels in finaImage
lineImage = np.zeros_like(iThresh, np.uint8)
for rho in range(min(rhoValues), max(rhoValues), 1):
    a = np.cos(maxTheta)
    b = np.sin(maxTheta)
    x0 = round(a*rho)
    y0 = round(b*rho)
    lineCount = 0
    pixelList = []
    for jump in range(-1000, 1000, 1):
        x1 = int(x0 + jump * (-b))
        y1 = int(y0 + jump * (a))
        if x1 < 0 or y1 < 0 or x1 >= lineImage.shape[1] or y1 >= lineImage.shape[0]:
            continue
        if iThreshRemove[y1, x1] == int(255):
            pixelList.append((y1, x1))
            lineCount += 1

    if lineCount > minLineCount:
        for y,x in pixelList:
            lineImage[y, x] = int(255)

# Remove small areas

## Opencv 2.4
im2, contours, hierarchy = cv2.findContours(lineImage,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE )

finalImage = np.zeros_like(lineImage)
finalShapes = []
for contour in contours:
    if contour.size > minArea:
        finalShapes.append(contour)

cv2.fillPoly(finalImage, finalShapes, 255)
## Opencv 3.0
# output = cv2.connectedComponentsWithStats(lineImage, 8, cv2.CV_32S)
#
# finalImage = np.zeros_like(output[1])
# finalImage = output[1]
# stat = output[2]
# for label in range(output[0]):
#     if label == 0:
#         continue
#     cc = stat[label,:]
#     if cc[cv2.CC_STAT_AREA] < minArea:
#         finalImage[finalImage == label] = 0
#     else:
#         finalImage[finalImage == label] = 255

# Show image
#cv2.imwrite('finalImage2.jpg',finalImage)
cv2.imshow('a', finalImage.astype(np.uint8))
cv2.waitKey(0)

and the result for the images: Result

enter image description here

Upvotes: 1

Tes3awy
Tes3awy

Reputation: 2266

STILL IN PROGRESS

First of all, an RGB image consists of 3 grayscale images. Since you need the green color you will deal only with one channel. The green one. To do so, you can split the image, you can use b,g,r = cv2.split('Your Image'). You will get an output like that if you are showing the green channel:

green_channel

After that you should threshold the image using your desired way. I prefer Otsu's thresholding in this case. The output after thresholding is:

thresholded_image

It's obvious that the thresholded image is extremley noisy. So performing erosion will reduce the noise a little bit. The noise reduced image will be similar to the following:

erosion

I tried using closing instead of dilation, but closing preserves some unwanted noise. So I separately performed erosion followed by dilation. After dilation the output is:

dilation

Note that: You can do your own way in morphological operation. You can use opening instead of what I did. The results are subjective from one person to another.

Now you can try one these two methods:

1. Blob Detection. 2. HoughLine Transform.

TODO

Try out these two methods and choose the best.

Upvotes: 1

Related Questions