以下是我正在使用的示例图片:
在每张图片上都有一个测量条。测量条的尺寸和角度可以变化。我已经确定了与测量条的某些交叉点,现在需要确定它对应的数字(例如256,192,128 ......)。所以我需要识别像素范围并将每个像素映射到一个数字。为了识别这些范围,似乎唯一的方法是检测每个数字旁边的小线并将它们连接成一个更大的线。
我的计划是隔离这些小的测量线,然后使用HoughTransform连接它们之间的线,但是我发现很难隔离这些小线。我尝试过Canny边缘检测,但小的测量线总是作为垂直边缘的一部分被检测到。我尝试了很多不同的门槛和升级,没有成功。
img = cv2.imread('example.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
resized = cv2.resize(gray,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
blur_gray = cv2.GaussianBlur(resized,(5, 5),0)
edges = cv2.Canny(blur_gray, 100, 200)
升级x2 vs 升级x10
这甚至是正确的方法还是我可以使用另一种方法来提取这些测量线?
答案 0 :(得分:2)
我会采取以下方法:
cv2.HoughLinesP()
检测长直线find_peaks
参数的 distance
来检测标记/文本之间的白色区域。import cv2
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import find_peaks
from skimage.draw import line
NOF_MARKERS = 30
# Show input image
img = cv2.imread("mPIXY.jpg")
img_orig = img.copy()
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
fig, axs = plt.subplots(2, 2)
# Detect long lines in the image
img_edg = cv2.Canny(img, 50, 120)
img_edg = cv2.morphologyEx(img_edg, cv2.MORPH_CLOSE, (5, 5), iterations=1)
img_edg = cv2.cvtColor(img_edg, cv2.COLOR_GRAY2RGB)
axs[0, 0].set_title("Canny edges + morphology closed")
axs[0, 0].imshow(img_edg)
lines = cv2.HoughLinesP(
img_edg[:, :, 0].copy(),
rho=1,
theta=np.pi / 360,
threshold=70,
minLineLength=300,
maxLineGap=15,
)
lines = lines.squeeze()
for x1, y1, x2, y2 in lines:
cv2.line(img_edg, (x1, y1), (x2, y2), (255, 0, 0))
axs[0, 0].imshow(img_edg, aspect="auto")
def optimize_line_alignment(img_gray, line_end_points):
# Shift endpoints to find optimal alignment with black line in the origial image
opt_line_mean = 255
x1, y1, x2, y2 = line_end_points
for dx1 in range(-3, 4):
for dy1 in range(-3, 4):
for dx2 in range(-3, 4):
for dy2 in range(-3, 4):
line_discrete = np.asarray(
list(zip(*line(*(x1 + dx1, y1 + dy1), *(x2 + dx2, y2 + dy2))))
)
line_pixel_values = img_gray[
line_discrete[:, 1], line_discrete[:, 0]
]
line_mean = np.mean(line_pixel_values)
if line_mean < opt_line_mean:
opt_line_end_points = np.array(
[x1 + dx1, y1 + dy1, x2 + dx2, y2 + dy2]
)
opt_line_discrete = line_discrete
opt_line_mean = line_mean
return opt_line_end_points, opt_line_discrete
# Optimize alignment for the 2 outermost lines
dx = np.mean(abs(lines[:, 2] - lines[:, 0]))
dy = np.mean(abs(lines[:, 3] - lines[:, 1]))
if dy > dx:
lines = lines[np.argsort(lines[:, 0]), :]
else:
lines = lines[np.argsort(lines[:, 1]), :]
line1, line1_discrete = optimize_line_alignment(img_gray, lines[0, :])
line2, line2_discrete = optimize_line_alignment(img_gray, lines[-1, :])
cv2.line(img, (line1[0], line1[1]), (line1[2], line1[3]), (255, 0, 0))
cv2.line(img, (line2[0], line2[1]), (line2[2], line2[3]), (255, 0, 0))
axs[0, 1].set_title("Edges of the strip")
axs[0, 1].imshow(img, aspect="auto")
# Take region of interest from image
dx = round(0.5 * (line2[0] - line1[0]) + 0.5 * (line2[2] - line1[2]))
dy = round(0.5 * (line2[1] - line1[1]) + 0.5 * (line2[3] - line1[3]))
strip_width = len(list(zip(*line(*(0, 0), *(dx, dy)))))
img_roi = np.zeros((strip_width, line1_discrete.shape[0]), dtype=np.uint8)
for idx, (x, y) in enumerate(line1_discrete):
perpendicular_line_discrete = np.asarray(
list(zip(*line(*(x, y), *(x + dx, y + dy))))
)
img_roi[:, idx] = img_gray[
perpendicular_line_discrete[:, 1], perpendicular_line_discrete[:, 0]
]
axs[1, 0].set_title("Strip analysis")
axs[1, 0].imshow(img_roi, cmap="gray")
extra_ax = axs[1, 0].twinx()
roi_mean = np.mean(img_roi, axis=0)
extra_ax.plot(roi_mean, label="mean")
extra_ax.plot(np.min(roi_mean, axis=0), label="min")
plt.legend()
# Locate the markers within region of interest
black_bar = np.argmin(roi_mean)
length = np.max([img_roi.shape[1] - black_bar, black_bar])
if black_bar < img_roi.shape[1] / 2:
roi_mean = np.append(roi_mean, 0)
peaks, _ = find_peaks(roi_mean[black_bar:], distance=length / NOF_MARKERS * 0.75)
peaks = peaks + black_bar
else:
roi_mean = np.insert(roi_mean, 0, 0)
peaks, _ = find_peaks(roi_mean[:black_bar], distance=length / NOF_MARKERS * 0.75)
peaks = peaks - 1
extra_ax.vlines(
peaks,
extra_ax.get_ylim()[0],
extra_ax.get_ylim()[1],
colors="green",
linestyles="dotted",
)
axs[1, 1].set_title("Midpoints between markings")
axs[1, 1].imshow(img_orig, aspect="auto")
axs[1, 1].plot(line1_discrete[peaks, 0], line1_discrete[peaks, 1], "r+")
fig.show()