pythonopencvimage-processingstraight-line-detection

Line detection of noisy and blurry image


There is a noisy and blurry image that contains an edge that must be detected. The edge is clearly visible to the human eye, but I'm having trouble letting OpenCV detect it.

The image in question: bad quality image

You need to adjust the contrast and brightness to see it. I only wanted to post the original image.

The edge that is to be detected is the thick black one that runs horizontally, after the ROI is applied. Here is what I have tried so far:

import numpy as np
from PIL import Image
import cv2

file = "input3.tif"
im = Image.open(file)
imarray = np.array(im)
roi = imarray[230:310, 460:660]
img8 = (roi/2).astype('uint8')
cv2.imshow('img8', img8)

blur = cv2.bilateralFilter(img8,9,5,150)
cv2.imshow('blur', blur)

kernel = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]])
sharpened = cv2.filter2D(blur, -1, kernel)
cv2.imshow('sharpened', sharpened)

edges = cv2.Canny(sharpened,150, 250, apertureSize=3)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 20, minLineLength=100, maxLineGap=8)
for line in lines:
    for x1, y1, x2, y2 in line:
        cv2.line(img8, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imshow('out', img8)

With the undesired

result.

What improvements can be made so that only the horizontal edge is detected?


Solution

  • as others suggested, it would be much easier to use cv2.equalizeHist to correct the image, the following code worked well for me:

    im = cv2.cvtColor(cv2.imread("unsharp.jpg"),cv2.COLOR_BGR2RGB) # read as rgb for easy plotting
    gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY) # convert to gray
    roi = gray[230:310, 460:660].copy() # copy to roi
    imHistEqual = cv2.equalizeHist(roi) # equalize
    edges = cv2.Canny(imHistEqual,150, 250, apertureSize=3) # detect edges
    lines = cv2.HoughLinesP(edges, 1, np.pi/180, 20, minLineLength=50, maxLineGap=8) # detect lines, corrected minLineLength to 50
    roiContoured = roi.copy() # copy for contouring
    # for loop to draw lines
    for line in lines:
        for x1, y1, x2, y2 in line:
            cv2.line(roiContoured, (x1, y1), (x2, y2), (255, 255, 255), 3)
    

    The results are like this:

    Results

    Also, the minLineLength of 100 which you set before was a bit too much, I lowered it to 50 and the horizontal line was detected.

    Some info about the plots, all are plotted like this:

    fig, ax = plt.subplots(nrows = 3, ncols = 1, sharex = True, sharey = True)
    ax[0].imshow(roi, cmap = "gray", vmin = 0, vmax = 255)
    ax[1].imshow(imHistEqual, cmap = "gray", vmin = 0, vmax = 255)
    ax[2].imshow(roiContoured, cmap = "gray", vmin = 0, vmax = 255)
    ax[0].axis("off")
    ax[1].axis("off")
    ax[2].axis("off")
    ax[0].set_title("roi")
    ax[1].set_title("after cv2.equalizeHist")
    ax[2].set_title("after line detection")
    plt.show()
    plt.savefig("LineDetection.png", dpi = 330)