两行之间的像素强度值

2024-09-24 02:25:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经创建了一个alghoritm,它可以检测挤出的colagen套管的边缘,并在图像上的这些边缘之间绘制一条中心线Casing with a centerline

这是我的密码:

import numpy as np
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')

img = cv2.imread("C:/Users/5.jpg", cv2.IMREAD_GRAYSCALE)
img = cv2.resize(img, (1500, 1200))

#ROI
fromCenter = False
r = cv2.selectROI(img, fromCenter)
imCrop = img[int(r[1]):int(r[1]+r[3]), int(r[0]):int(r[0]+r[2])]

#Operations on an image
_,thresh = cv2.threshold(imCrop,100,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)

blur = cv2.GaussianBlur(opening,(7,7),0)

edges = cv2.Canny(blur, 0,20)

#Edges localization, packing coords into a list
indices = np.where(edges != [0])
coordinates = list(zip(indices[1], indices[0]))
num = len(coordinates)

#Separating into top and bot edge
bot_cor = coordinates[:int(num/2)]
top_cor = coordinates[-int(num/2):]

#Converting to arrays, sorting
a, b = np.array(top_cor), np.array(bot_cor)
a, b = a[a[:,0].argsort()], b[b[:,0].argsort()]

#Edges approximation by a 5th degree polynomial
min_a_x, max_a_x = np.min(a[:,0]), np.max(a[:,0])
new_a_x = np.linspace(min_a_x, max_a_x, imCrop.shape[1])
a_coefs = np.polyfit(a[:,0],a[:,1], 5)
new_a_y = np.polyval(a_coefs, new_a_x)

min_b_x, max_b_x = np.min(b[:,0]), np.max(b[:,0])
new_b_x = np.linspace(min_b_x, max_b_x, imCrop.shape[1])
b_coefs = np.polyfit(b[:,0],b[:,1], 5)
new_b_y = np.polyval(b_coefs, new_b_x)

#Defining a centerline
midx = [np.average([new_a_x[i], new_b_x[i]], axis = 0) for i in range(imCrop.shape[1])]
midy = [np.average([new_a_y[i], new_b_y[i]], axis = 0) for i in range(imCrop.shape[1])]

plt.figure(figsize=(16,8))
plt.title('Cross section')
plt.xlabel('Length of the casing', fontsize=18)
plt.ylabel('Width of the casing', fontsize=18)
plt.plot(new_a_x, new_a_y,c='black')
plt.plot(new_b_x, new_b_y,c='black')
plt.plot(midx, midy, '-', c='blue')
plt.show()

#Converting coords type to a list (plotting purposes)
coords = list(zip(midx, midy))
points = list(np.int_(coords))

mask = np.zeros((imCrop.shape[:2]), np.uint8)
mask = edges

#Plotting
for point in points:
    cv2.circle(mask, tuple(point), 1, (255,255,255), -1)

for point in points:
    cv2.circle(imCrop, tuple(point), 1, (255,255,255), -1)  

cv2.imshow('imCrop', imCrop)
cv2.imshow('mask', mask)

cv2.waitKey(0)
cv2.destroyAllWindows()

现在我想总结一下上边缘和中心线之间区域中每个像素的强度(对于中心线和下边缘之间的区域也是如此)

有没有办法将ROI限制在检测到的边缘之间的区域,并根据计算出的中心线将其分割为两个区域

或者是否有任何方法可以根据边缘和中心线之间的坐标访问像素

(这是我在这里的第一篇帖子,为所有的错误提前道歉)


Tags: imgnewnppltmaskcoordsmincv2
1条回答
网友
1楼 · 发布于 2024-09-24 02:25:35

我写了一个有点幼稚的代码来获得上下部分的面具。我的代码认为源图像将始终像您的一样:带有水平条纹

应用Canny后,我得到以下结果:

enter image description here

然后我在图像数组中运行一些循环,以填充图像中不需要的区域。这是分别为上部和下部完成的,创建遮罩。结果是:

enter image description here

然后,您可以使用cv.sumElems使用此掩码仅对感兴趣的元素求和

import cv2 as cv

#open as grayscale image
src = cv.imread("colagen.png",cv.IMREAD_GRAYSCALE)

# apply canny and find contours
threshold = 100
canny_output = cv.Canny(src, threshold, threshold * 2)

# find mask for upper part
mask1 = canny_output.copy()
x, y = canny_output.shape
area = 0
for j in range(y):
    area = 0
    for i in range(x):
        if area == 0:
            if mask1[i][j] > 0:
                area = 1
                continue
            else: 
                mask1[i][j] = 255
        elif area == 1:
            if mask1[i][j] > 0:
                area = 2
            else: 
                continue
        else:
            mask1[i][j] = 255
mask1 = cv.bitwise_not(mask1)

# find mask for lower part         
mask2 = canny_output.copy()
x, y = canny_output.shape
area = 0
for j in range(y):
    area = 0
    for i in range(x):
        if area == 0:
            if mask2[-i][j] > 0:
                area = 1
                continue
            else: 
                mask2[-i][j] = 255
        elif area == 1:
            if mask2[-i][j] > 0:
                area = 2
            else: 
                continue
        else:
            mask2[-i][j] = 255
mask2 = cv.bitwise_not(mask2)

# apply masks and calculate sum of elements in upper and lower part
sums = [0,0]
(sums[0],_,_,_) = cv.sumElems(cv.bitwise_and(src,mask1))
(sums[1],_,_,_) = cv.sumElems(cv.bitwise_and(src,mask2))

cv.imshow('src',src)
cv.imshow('canny',canny_output)
cv.imshow('mask1',mask1)
cv.imshow('mask2',mask2)
cv.imshow('masked1',cv.bitwise_and(src,mask1))
cv.imshow('masked2',cv.bitwise_and(src,mask2))
cv.waitKey()

备选方案…

可能存在一些函数来填充Canny结果的区域。我尝试了cv.fillPolycv.floodFill,但没能让它们轻松工作。。。但是也许其他人可以帮你

编辑

找到了另一种方法,用更干净的代码获得面具。使用numpynp.add.accumulate然后np.clip,然后使用模运算:

# first divide canny_output by 255 to get 0's and 1's, then perform
# an accumulate addition for each column. Thus you'll get +1 for every
# line, "painting" areas with 1, 2, 3...
a = np.add.accumulate(canny_output/255,0)
# clip values: anything greater than 2 becomes 2
a = np.clip(a, 0, 2)
# performe a modulo, to get areas alternating with 0 or 1; then multiply by 255
a = a%2 * 255
# convert to uint8
mask1 = cv.convertScaleAbs(a)

# to get mask2 (the lower mask) flip the array then do the same as above
a = np.add.accumulate(np.flip(canny_output,0)/255,0)
a = np.clip(a, 0, 2)
a = a%2 * 255
mask2 = cv.convertScaleAbs(np.flip(a,0))

这将返回几乎相同的结果。面具的边缘有点不同

相关问题 更多 >