寻找不同的苹果图像分割方法

2024-04-19 04:00:26 发布

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

我有被碘溶液浸泡过的苹果片的照片。目标是将苹果分割成感兴趣的各个区域,并评估每个区域的淀粉水平。这是一个学校项目,所以我的目标是测试不同的分割方法,客观地找到最好的解决方案,无论是单一技术还是多种技术的组合

问题是,到目前为止,我只接近于一种方法。这种方法是使用霍夫圆。我最初计划使用分水岭方法、形态学操作或简单阈值。这个计划失败了,因为我无法修改它们中的任何一个

原始图像看起来与此相似,苹果的黑暗程度各不相同

The original images look similar to this, with varying shades of darkness of the apple

我尝试过使用cv2.inRange和HSV值来移除背景托盘,但是对于深色的苹果来说效果不好

这是HoughCircles在原始图像上生成的,应用了灰度和中值模糊,还尝试了托盘遮罩

This is what the HoughCircles produced on the original image with a grayscale and median blur applied, also with an attempted mask of the tray.

任何关于下一步行动方向的建议都将不胜感激。如果有帮助的话,我可以提供我正在使用的代码

谢谢大家!

编辑1:添加一些代码并澄清问题

谢谢你的回复。我真正的问题是,有没有其他的分割方法适合这个场景?我想尝试两种不同的方法,并在一大组照片上比较结果。我下一步要尝试的是使用k-means分割。此外,我将在下面添加一些代码,以显示我迄今为止所做的尝试

HSV颜色过滤

import cv2
import numpy as np

# Load image
image = cv2.imread('ApplePic.jpg')

# Set minimum and max HSV values to display
lower = np.array([0, 0, 0])
upper = np.array([105, 200, 255])

# Create HSV Image and threshold into a range.
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower, upper)
maskedImage = cv2.bitwise_and(image, image, mask=mask)

# Show Image
cv2.imshow('HSV Mask', image)
cv2.waitKey(0)

霍格圈

# import the necessary packages
import numpy as np
import argparse
import cv2
import os

directory = os.fsencode('Photos\\Sample N 100')

for file in os.listdir(directory):

    filename = os.fsdecode(file)

    if filename.endswith('.jpg'):
        # Load the image
        image = cv2.imread('Photos\\Sample N 100\\' + filename)

        # Calculate scale
        scale_factor = 800 / image.shape[0]
        width = int(image.shape[1] * scale_factor)
        height = 800
        dimension = (width, height)
        min_radius = int((width / 10) * .8)
        max_radius = int((width / 10) * 1.2)

        # Resize image
        image = cv2.resize(image, dimension, interpolation=cv2.INTER_AREA)

        # Copy Image 
        output = image.copy()

        # Grayscale Image
        gray = cv2.medianBlur(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), 5)

        # Detect circles in image
        circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, min_radius * 2, 4, 60, 20,  min_radius, max_radius)

        # ensure at least some circles were found
        if circles is not None:
            # convert the (x, y) coordinates and radius of the circles to integers
            circles = np.round(circles[0, :]).astype("int")
            # loop over the (x, y) coordinates and radius of the circles
            for (x, y, r) in circles:
                # draw the circle in the output image, then draw a rectangle
                # corresponding to the center of the circle
                cv2.circle(output, (x, y), r, (0, 255, 0), 4)
                cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
                cv2.putText(output, '(' + str(x) + ',' + str(y) + ',' + str(r) + ')', (x, y),
                        cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, 255)


            # show the output image
            cv2.imshow("output", np.hstack([image, output, maskedImage]))
            cv2.waitKey(0)
        continue
    else:
        continue

Tags: andthe方法inimageimport苹果output
1条回答
网友
1楼 · 发布于 2024-04-19 04:00:26

分割苹果的另一种方法是在阈值化之前执行Kmeans颜色分割,然后使用轮廓滤波分离苹果对象:

  1. 应用Kmeans颜色分割。我们加载图像,使用^{}调整较小的大小,然后应用Kmeans颜色分割。根据簇的数量,我们可以将图像分割成所需数量的颜色

  2. 获得二值图像。接下来我们将转换为灰度、高斯模糊和大津阈值

  3. 使用轮廓近似进行过滤。我们过滤掉非圆形轮廓和小噪声

  4. 形态学操作。我们执行变形接近以填充相邻轮廓

  5. 使用轮廓面积作为过滤器绘制最小封闭圆。我们找到轮廓并绘制近似圆。为此,我们使用两个部分,一个是有一个好的阈值,另一个是我们近似半径


Kmeans使用clusters=3和二值图像进行颜色量化

变形闭合与结果

使用cv2.minEnclosingCircle自动计算半径的“良好”等高线以绿色突出显示,而近似等高线以teal突出显示。这些近似轮廓没有从阈值过程中很好地分割出来,因此我们平均“良好”轮廓半径,并使用该半径绘制圆

代码

import cv2
import numpy as np
import imutils

# Kmeans color segmentation
def kmeans_color_quantization(image, clusters=8, rounds=1):
    h, w = image.shape[:2]
    samples = np.zeros([h*w,3], dtype=np.float32)
    count = 0

    for x in range(h):
        for y in range(w):
            samples[count] = image[x][y]
            count += 1

    compactness, labels, centers = cv2.kmeans(samples,
            clusters, 
            None,
            (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10000, 0.0001), 
            rounds, 
            cv2.KMEANS_RANDOM_CENTERS)

    centers = np.uint8(centers)
    res = centers[labels.flatten()]
    return res.reshape((image.shape))

# Load image, resize smaller, perform kmeans, grayscale
# Apply Gaussian blur, Otsu's threshold
image = cv2.imread('1.jpg')
image = imutils.resize(image, width=600)
kmeans = kmeans_color_quantization(image, clusters=3)
gray = cv2.cvtColor(kmeans, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (9,9), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Filter out contours not circle
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.04 * peri, True)
    if len(approx) < 4:
        cv2.drawContours(thresh, [c], -1, 0, -1)

# Morph close
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=3)

# Find contours and draw minimum enclosing circles 
# using contour area as filter
approximated_radius = 63
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    x,y,w,h = cv2.boundingRect(c)
    # Large circles
    if area > 6000 and area < 15000:
        ((x, y), r) = cv2.minEnclosingCircle(c)
        cv2.circle(image, (int(x), int(y)), int(r), (36, 255, 12), 2)
    # Small circles
    elif area > 1000 and area < 6000:
        ((x, y), r) = cv2.minEnclosingCircle(c)
        cv2.circle(image, (int(x), int(y)), approximated_radius, (200, 255, 12), 2)

cv2.imshow('kmeans', kmeans)
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.waitKey()     

相关问题 更多 >