如何使用 OpenCV 获取图像中多个对象(例如扁豆种子)的平均 RGB 值

How to get mean RGB value of multiple objects (for eg. lentil seeds) in an image using OpenCV

我使用的图像包括放置在最左侧的用于 pixel_per_metric 参数的硬币,以及放置在其右侧的 5 个扁豆种子,它们大致呈圆形,它们是黄色的。 我无法获得每个小扁豆种子的单独平均 RGB 值。

此代码允许我计算种子的大小,但不能计算每个种子的平均 rgb 值

请建议对此代码进行一些更改,以便我可以计算每个种子的平均 RGB 值。

在 Internet 上,人们建议创建一个可以执行此操作的蒙版,但我不确定如何执行此操作以获得 RGB 值。预期的输出只是获取所有对象的大小以及获取所有对象的平均 RGB 或 BGR 值。

width参数就是一枚硬币的宽度,可以取2.4(cm)

下面是图片link

https://drive.google.com/file/d/16ktHYpy-YcOFnHrcZ1E13AwzJiC2bxZt/view?usp=drivesdk

提前致谢

我的代码:

# import the necessary packages
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2

def midpoint(ptA, ptB):
    return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
    help="path to the input image")
ap.add_argument("-w", "--width", type=float, required=True,
    help="width of the left-most object in the image (in cm)")
args = vars(ap.parse_args())

# load the image, convert it to grayscale, and blur it slightly
image = cv2.imread(args["image"])
image4 = cv2.imread(args["image"])
image=cv2.resize(image,(900,1200))
hsv = cv2.cvtColor(image,cv2.COLOR_BGR2HSV)

# Range for lower red (if the seed was red) 
lower_red = np.array([8,120,70])
upper_red = np.array([35,255,255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)
#cv2.imshow('color',mask1)

res = cv2.bitwise_and(image,image,mask = mask1)
cv2.imshow('res',res)
gray2 = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
gray2 = cv2.GaussianBlur(gray2, (7, 7), 0)

# perform edge detection, then perform a dilation + erosion to
# close gaps in between object edges
edged = cv2.Canny(gray2, 50, 100)
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)

# find contours in the edge map
cnts2 = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts2 = imutils.grab_contours(cnts2)
cv2.drawContours(res,cnts2,-1,(0,255,0))
#cv2.imshow('contours asli part2',res)
#cv2.waitKey(0)


gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)

# perform edge detection, then perform a dilation + erosion to
# close gaps in between object edges
edged1 = cv2.Canny(gray, 50, 100)
edged2 = cv2.dilate(edged1, None, iterations=1)
edged3 = cv2.erode(edged2, None, iterations=1)

# find contours in the edge map
cnts = cv2.findContours(edged3.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cv2.drawContours(image,cnts,-1,(0,255,0))
#cv2.imshow('contours asli',image)
#cv2.waitKey(0)


# sort the contours from left-to-right and initialize the
# 'pixels per metric' calibration variable
(cnts, _) = contours.sort_contours(cnts)
pixelsPerMetric = None


# loop over the contours individually
for c in cnts:
    # if the contour is not sufficiently large, ignore it
    if cv2.contourArea(c) < 100:
        continue

    # compute the rotated bounding box of the contour
    orig = image.copy()
    box = cv2.minAreaRect(c)
    box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
    box = np.array(box, dtype="int")

    # order the points in the contour such that they appear
    # in top-left, top-right, bottom-right, and bottom-left
    # order, then draw the outline of the rotated bounding
    # box
    box = perspective.order_points(box)
    cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)


    # loop over the original points and draw them
    for (x, y) in box:
        cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)

    # unpack the ordered bounding box, then compute the midpoint
    # between the top-left and top-right coordinates, followed by
    # the midpoint between bottom-left and bottom-right coordinates
    (tl, tr, br, bl) = box
    (tltrX, tltrY) = midpoint(tl, tr)
    (blbrX, blbrY) = midpoint(bl, br)

    # compute the midpoint between the top-left and top-right points,
    # followed by the midpoint between the top-righ and bottom-right
    (tlblX, tlblY) = midpoint(tl, bl)
    (trbrX, trbrY) = midpoint(tr, br)

    # draw the midpoints on the image
    cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
    cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
    cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
    cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)

    # draw lines between the midpoints
    cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
        (255, 0, 255), 2)
    cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
        (255, 0, 255), 2)

    # compute the Euclidean distance between the midpoints
    dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
    dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))

    # if the pixels per metric has not been initialized, then
    # compute it as the ratio of pixels to supplied metric
    # (in this case, inches)
    if pixelsPerMetric is None:
        pixelsPerMetric = dB / args["width"]

    # compute the size of the object
    dimA = dA / pixelsPerMetric
    dimB = dB / pixelsPerMetric

    # draw the object sizes on the image
    cv2.putText(orig, "{:.1f}cm".format(dimA),
        (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
        0.65, (255, 255, 255), 2)
    cv2.putText(orig, "{:.1f}cm".format(dimB),
        (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
        0.65, (255, 255, 255), 2)

    #show the output image
    cv2.imshow("Image", orig)
    cv2.waitKey(0)

以下方法需要 2 个参数。

def getMean(contour, img):
    #First parameter is the contour iside which the mean has to be calculated
    #Second parameter is the color image. Assuming 3 channels
    #Create a mask image representing the currently selected contour
    maskImage = np.zeros((img.shape[0], img.shape[1])).astype(np.uint8)
    cv2.drawContours(maskImage, [c],-1,1,-1)
    #get the RGB value of mean of the img inside the mask
    meanColor = np.array(cv2.mean(img, mask=maskImage)).astype(np.uint8)
    #create a temp image that has the average RGB color in mask and 0 elsewhere
    tempImage = np.zeros(image.shape).astype(np.uint8)
    tempImage[maskImage == 1] = meanColor[0:3]
    cv2.imshow("mask", tempImage)
    cv2.waitKey(0)