Python 收集所有不同轮廓的非零像素

Python 收集所有不同轮廓的非零像素,python,opencv,image-processing,Python,Opencv,Image Processing,我一直在尝试根据一个序列对轮廓进行排序,这个序列在这里并不重要。我有一个非常小的问题,那就是我应该在下面的代码段中传递的正确的numpy数组,我同时获得正确的行/列非零像素 row_pixels=cv2.countNonZero(blur[cy][:]) col_pixels=cv2.countNonZero(blur[:,cx]) 我所做的是得到如下结果:对于所有的5个轮廓,我得到的非零像素数量几乎相同,我意识到这是因为我传递了整个图像,正如你所看到的,上面的模糊是整个图像,作为计算像素的

我一直在尝试根据一个序列对轮廓进行排序,这个序列在这里并不重要。我有一个非常小的问题,那就是我应该在下面的代码段中传递的正确的numpy数组,我同时获得正确的行/列非零像素

row_pixels=cv2.countNonZero(blur[cy][:])

col_pixels=cv2.countNonZero(blur[:,cx])
我所做的是得到如下结果:对于所有的5个轮廓,我得到的非零像素数量几乎相同,我意识到这是因为我传递了整个图像,正如你所看到的,上面的模糊是整个图像,作为计算像素的numpy数组,这是错误的,我意识到了这一点

当前输入:不带标记的下图

预期输出:对于所有5个轮廓,行/列非零像素

我目前正在做的是:

import cv2
import numpy as np
from imutils import perspective
from imutils import contours 
import imutils 
from scipy.spatial import distance as dist
import argparse
import pandas as pd
import time

parser = argparse.ArgumentParser(description='Object Detection and Tracking using YOLO in OPENCV')
parser.add_argument('--image', help='Path to image file.')

args = parser.parse_args()
font=cv2.FONT_HERSHEY_SIMPLEX


start=time.time()
im_in = cv2.imread(args.image, 0)
_, thres2=cv2.threshold(im_in, 140, 255,cv2.THRESH_BINARY_INV)
dilate = cv2.dilate(thres2,None)
erode = cv2.erode(dilate,None)

im_3=erode.copy()

blur=cv2.medianBlur(im_3,5)

a=[]
r=[] 
row_col_pixel_values=[]
cl=[]
data=[]
global mainar
#find contours 
_,contour2,_=cv2.findContours(blur,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
# print(contour2)
for c in contour2:
    area=cv2.contourArea(c)
    if area>10000 and area <30000:
        a.append(area)

        cv2.drawContours(blur, [c], 0, (128, 128, 128), 1)


        M=cv2.moments(c)
        cx=int((M["m10"]/M["m00"]))
        cy=int((M["m01"]/M["m00"]))
        center =(cx,cy)
        data.append((cx,cy))
        cv2.circle(blur,(cx,cy), 5,(128,128,128),-1)
        print("",cx,cy)
        print(len(blur[cy][:])) 
        # one=blur[c]
        row_pixels=cv2.countNonZero(blur[cy][:])

        col_pixels=cv2.countNonZero(blur[:,cx])
        comb=(row_pixels,col_pixels)
        cl.append(comb)

nparea=np.array(a)
npcentercoord=np.array(data)

row_col_pixel_values=np.array(cl)
print("Area of 5 contours :",nparea)
print("Center coordinates of 5 contours:",npcentercoord)

print("Row and Column pixel values of 5 contours:",row_col_pixel_values)

mainar=np.column_stack((nparea,npcentercoord,row_col_pixel_values))
# print(mainar)

mainar[:,[1]] = (mainar[:,[1]]).astype(int)

MinX = int(min([_[1] for _ in mainar]))
MinlowerX = (MinX - 10) 
MinupperX = (MinX + 10)
MinY = int(min([_[2] for _ in mainar]))
MinlowerY = (MinY - 10) 
MinupperY = (MinY + 10)
MaxX = int(max([_[1] for _ in mainar]))
MaxlowerX = (MaxX - 10) 
MaxupperX = (MaxX + 10)
MaxY = int(max([_[2] for _ in mainar]))
MaxlowerY = (MaxY - 10)
MaxupperY = (MaxY + 10)

print("", MinX,MinY,MaxX,MaxY)


def PixeltoNumeric(channel,rowMM,colMM):

    if channel=="4S":
        for i in range(0, len(mainar[:,1])):
            cx=mainar[i,1]
            cy=mainar[i,2]
            if (cx in range(MinlowerX,MinupperX+1)) and (cy in range(MinlowerY,MinupperY+1)):
                rowp=mainar[i,3]
                colp=mainar[i,4]
                print("The center coordinates(x,y) and (Row/Col) pixels of 4Schannel: ")
                print("1 pixel has {:.5f} many mm in row:".format(rowMM/rowp))
                print("1 pixel has {:.5f} many mm in col:".format(colMM/colp))
                print(cx,cy,rowp,colp)

    if channel == '1':
            for i in range(0, len(mainar[:,1])):
                cx=mainar[i,1]
                cy=mainar[i,2]
                if (cx in range(MaxlowerX,MaxupperX+1)) and (cy in range(MaxlowerY,MaxupperY+1)):
                    rowp=mainar[i,3]
                    colp=mainar[i,4]
                    print("The center coordinates(x,y) and (Row/Col) pixels of 1Channel: ")
                    print("1 pixel has {:.5f} many mm in row:".format(rowMM/rowp))
                    print("1 pixel has {:.5f} many mm in col:".format(colMM/colp))
                    print(cx,cy,rowp,colp)

    if channel == '2':
        for i in range(0, len(mainar[:,1])):
            cx=mainar[i,1]
            cy=mainar[i,2]
            if (cx in range(MinlowerX,MinupperX+1)) and (cy in range(MaxlowerY,MaxupperY+1)):
                rowp=mainar[i,3]
                colp=mainar[i,4]
                print("The center coordinates(x,y) and (Row/Col) pixels of 2Channel: ")
                print("1 pixel has {:.5f} many mm in row:".format(rowMM/rowp))
                print("1 pixel has {:.5f} many mm in col:".format(colMM/colp))
                print(cx,cy,rowp,colp)

    if channel == '3':
        for i in range(0, len(mainar[:,1])):
            cx=mainar[i,1]
            cy=mainar[i,2]
            if (cx in range(((MinlowerX+MaxlowerX)//2),((MinupperX+MaxupperX+1)//2)) and (cy in range(((MinlowerY+MaxlowerY)//2),((MinupperY+MaxupperY+1)//2)))):
                rowp=mainar[i,3]
                colp=mainar[i,4]
                print("The center coordinates(x,y) and (Row/Col) pixels of 3Channel: ")
                print("1 pixel has {:.5f} many mm in row:".format(rowMM/rowp))
                print("1 pixel has {:.5f} many mm in col:".format(colMM/colp))
                print(cx,cy,rowp,colp)

    if channel == '4N':
        for i in range(0, len(mainar[:,1])):
            cx=mainar[i,1]
            cy=mainar[i,2]
            if (cx in range(MaxlowerX,MaxupperX+1)) and (cy in range(MinlowerY,MinupperY+1)):
                rowp=mainar[i,3]
                colp=mainar[i,4]
                print("The center coordinates(x,y) and (Row/Col) pixels of 4NChannel: ")
                print("1 pixel has {:.5f} many mm in row:".format(rowMM/rowp))
                print("1 pixel has {:.5f} many mm in col:".format(colMM/colp))
                print(cx,cy,rowp,colp)

    return (cv2.imshow("4",blur))


cv2.waitKey(0)
cv2.destroyAllWindows()

我不能完全确定我是否正确理解您,但我的理解是您希望找到所有轮廓内像素的所有坐标x,y。如果这是您的问题,您可以通过以下代码实现:

import cv2
import matplotlib.pyplot as plt
import numpy as np

im_in = cv2.imread(r'image.png', 0)
_, thres2 = cv2.threshold(im_in, 140, 255, cv2.THRESH_BINARY_INV)
dilate = cv2.dilate(thres2, None)
erode = cv2.erode(dilate, None)
im_3 = erode.copy()
blur = cv2.medianBlur(im_3, 5)

# I am using OpenCV 4 therefore it returns only 4 parameters
contour2, _ = cv2.findContours(blur, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
extracted = np.zeros(blur.shape, np.uint8)

for c in contour2:
    area = cv2.contourArea(c)
    # I have modified these values to make it work for attached picture
    if 10000 < area < 300000: 
        cv2.drawContours(extracted, [c], 0, (255), cv2.FILLED)

contour_x, contour_y = np.nonzero(extracted)

plt.imshow(extracted, 'gray')
plt.show()
这是提取的

更新1 经过您的解释,我知道您想要计算每个单独轮廓的宽度和高度。根据您提供的示例代码,我假设您希望使用穿过轮廓中心的线来测量宽度和高度。您可以通过在清晰的图像上绘制和测量轮廓来实现这一点。请参阅下面的代码:

# I am using OpenCV 4 therefore it returns only 4 parameters
contour2, _ = cv2.findContours(blur, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
extracted = np.zeros(blur.shape, np.uint8)
contoursSize = []
for c in contour2:
    area = cv2.contourArea(c)
    # I have modified these values to make it work for attached picture
    if 10000 < area < 300000:
        M = cv2.moments(c)
        cx = int((M["m10"] / M["m00"]))
        cy = int((M["m01"] / M["m00"]))
        extracted.fill(0) 
        cv2.drawContours(extracted, [c], 0, 255, cv2.FILLED)
        width = cv2.countNonZero(extracted[cy][:])
        height = cv2.countNonZero(extracted[:, cx])
        contoursSize.append((width, height))

您好,谢谢您的回复,我实际上是在计算您从图像中心提取的每个轮廓的宽度和高度。所以目前我得到的行/列像素是整个图像的非零像素。我希望在每个轮廓内计算这些像素:row_pixels=cv2.countNonZeroblur[cy][:]-这为整个图像而不是一个轮廓提供。如果你需要这些轮廓的宽度和高度,你可以使用函数cv2.boudingRect来获得轮廓的边界框。检查此代码:对于轮廓2中的c:rect=cv2.boundingRectc;printf'width:{rect[2]},height:{rect[3]}'我不能使用边界矩形,因为您看到中心轮廓是一条向内成形的曲线。通过该过程无法正确测量宽度。这就是为什么我转而计算轮廓内的白色像素。我根据你的解释编辑了我的帖子。就性能而言,这不是最好的解决方案,因此它可以在不绘制的情况下实现,只需处理轮廓中的点,但这是一个快速的胜利。不过,当我cv2.imshow提取时,一个小问题是,为什么我只看到一个白色轮廓。我得到了你的方法,你在原始图像上创建了一个黑色遮罩,并使用cv.FILLED计算了5个白色轮廓上的白色像素。但是当我得到图像的输出时,我只看到一个白色轮廓,尽管我得到了结果?我做错什么了吗:这个问题看起来很像