I want to find the dark gray diagonal line in this the background is quite noisy and has a gradient in brightness. (The line is barely visible when opening the .png but if I read it as grayscale the line becomes more pronounced.)
I tried different combinations of bluring, thresholding and canny edge detection. The best I could come up with was:
img_blur = cv.bilateralFilter(img, 3, 120, 120)
thresh = cv.adaptiveThreshold(img_blur, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 501, 3)
which results in this . Here there is still quite alot of noise in the background and the line is interrupted.
I tried some morphological operations (dilate, erode, open, close) but with no real improvement.
Applying something like lines = cv.HoughLines(thresh, rho=1, theta=np.pi / 180, threshold=130)
left me with this .
Which is what I wanted, but the threshold of 130 doesn't work for similar images and will find no or too many lines.
You can try to first detect ridges in the image using a Hessian, and then threshold. This seems to work okay on your example image.
import cv2
import numpy as np
import matplotlib.pyplot as plt
from skimage.feature import hessian_matrix, hessian_matrix_eigvals
def detect_ridges(img: np.ndarray, sigma: int = 3) -> np.ndarray:
img = cv2.equalizeHist(img.astype(np.uint8))
elements = hessian_matrix(img, sigma, use_gaussian_derivatives=False)
eigvals = hessian_matrix_eigvals(elements)
cv2.normalize(eigvals[0], eigvals[0], 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
return eigvals[0]
original_image = cv2.imread("zkN7m.png", cv2.IMREAD_GRAYSCALE)
ridges = detect_ridges(original_image)
thresholded = cv2.adaptiveThreshold((255-ridges).astype(np.uint8), 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 3, 2)
plt.imshow(thresholded, cmap="bone")