使用opencv-python对肉进行分析熟度

逻辑步骤

  • 获取图片转换为HSV色域空间(符合人类视觉逻辑,分析更准确)
  • 定义肉色的颜色范围,数据如下:(使用现写的Python脚本读取涂抹图片HSV值)
    lower_meat = np.array([1, 130, 100]) # 下限
    upper_meat = np.array([19, 240, 248]) # 上限
    
  •  创建肉串掩膜(就是把肉的色域范围的图片扣下来,类似抠图)
  • 使用形态学操作去除噪声(很有用,对图片开运算和闭运算,去除内外部分细节和噪声)
  • 然后去找轮廓,忽略过小轮廓
  • 对单个轮廓判断熟度,数据如下:(这个也用脚本去涂抹读取)
    # h_values: (1, 4) s_values: (162, 187) v_values: (126, 142) # 全生
    # h_values: (3, 5) s_values: (179, 218) v_values: (124, 159) # 微生
    # h_values: (3, 5) s_values: (160, 215) v_values: (126, 184) # 微生
    # h_values: (4, 7) s_values: (150, 176) v_values: (158, 182) # 微熟
    # h_values: (5, 9) s_values: (137, 169) v_values: (139, 156) # 微熟
    # h_values: (8, 10) s_values: (142, 160) v_values: (136, 158) # 全熟
    
  • 最后展示结果:
7b856d58b87e48aeb2ce81a469962814.png
 

代码,亲手敲的,不白嫖

import cv2
import numpy as np
from skimage import morphology
from PIL import Image, ImageDraw, ImageFont


# 获取不同颜色比例
def get_doneness(hsv_image, lower_color, upper_color, mask):
    masked_image = cv2.bitwise_and(hsv_image, hsv_image, mask=mask)
    color_mask = cv2.inRange(masked_image, lower_color, upper_color)
    ratio_color = cv2.countNonZero(color_mask) / cv2.countNonZero(mask)
    return ratio_color

def determine_doneness(ratio):
    if ratio == 0:
        return "全生"
    elif ratio == 1:
        return "微生"
    elif ratio == 2:
        return "微熟"
    elif ratio == 3:
        return "全熟"

# Opencv 中文支持
def put_chinese_text(image, text, position, font_size, color):
    # 将OpenCV图片转换为Pillow图片
    image_pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    # 创建一个Draw对象
    draw = ImageDraw.Draw(image_pil)
    # 加载字体
    font = ImageFont.truetype('./MSYH.TTC', font_size)
    # 绘制文本
    draw.text(position, text, font=font, fill=color)
    # 将Pillow图片转换回OpenCV图片
    image = cv2.cvtColor(np.array(image_pil), cv2.COLOR_RGB2BGR)
    return image


def main():
    # # 捕获摄像头图像
    # cap = cv2.VideoCapture(0)
    # if not cap.isOpened():
    #     print("Could not open camera")
    #     return

    while True:
        # ret, frame = cap.read()
        # frame = cv2.imread('kaorou.jpg')
        frame = cv2.imread('OIP-C (1).jpg')
        # if not ret:
        #     print("Failed to capture image")
        #     break

        # 转换为HSV颜色空间
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        cv2.imshow("HSV", hsv)

        # 竹签 hues:(20,20), saturations:(122,122), values:(250,250)

        # 定义肉串的颜色范围 
        lower_meat = np.array([1, 130, 100])
        upper_meat = np.array([19, 240, 248])

        # 创建肉串掩膜
        meat_mask = cv2.inRange(hsv, lower_meat, upper_meat)
        cv2.imshow("MASK", meat_mask)

        # 使用形态学操作去除噪声
        kernel = np.ones((5, 5), np.uint8)
        meat_mask = cv2.morphologyEx(meat_mask, cv2.MORPH_CLOSE, kernel)
        meat_mask = cv2.morphologyEx(meat_mask, cv2.MORPH_OPEN, kernel)
        # meat_mask = morphology.remove_small_objects(meat_mask, 700)
        cv2.imshow("remove noise", meat_mask)

        # 找到所有轮廓,去除小轮廓
        contours, _ = cv2.findContours(meat_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # 创建一个掩码,用于绘制保留的轮廓
        mask = np.ones_like(meat_mask) * 255
        for contour in contours:
            # 过滤小面积轮廓
            if cv2.contourArea(contour) < 600:
                cv2.drawContours(mask, [contour], -1, (0, 0, 0), thickness=cv2.FILLED)
        # 应用掩码
        meat_mask = cv2.bitwise_and(meat_mask, mask)
        cv2.imshow("remove noise1", meat_mask)

        # 找到肉串轮廓
        contours, _ = cv2.findContours(meat_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        doneness_results = []
        for contour in contours:
            if cv2.contourArea(contour) > 800:  # 忽略小轮廓
                x, y, w, h = cv2.boundingRect(contour)
                cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

                # 创建单个肉串的掩膜
                single_meat_mask = np.zeros_like(meat_mask)
                cv2.drawContours(single_meat_mask, [contour], -1, 255, thickness=cv2.FILLED)

                # h_values: (1, 4) s_values: (162, 187) v_values: (126, 142) # 全生
                # h_values: (3, 5) s_values: (179, 218) v_values: (124, 159) # 微生
                # h_values: (3, 5) s_values: (160, 215) v_values: (126, 184) # 微生
                # h_values: (4, 7) s_values: (150, 176) v_values: (158, 182) # 微熟
                # h_values: (5, 9) s_values: (137, 169) v_values: (139, 156) # 微熟
                # h_values: (8, 10) s_values: (142, 160) v_values: (136, 158) # 全熟

                
                # 获取不同颜色比例
                ratio_very_rare = get_doneness(hsv, np.array([1, 162, 126]), np.array([4, 187, 142]), single_meat_mask)
                ratio_rare = get_doneness(hsv, np.array([3, 160, 124]), np.array([5, 218, 184]), single_meat_mask)
                ratio_medium = get_doneness(hsv, np.array([4, 137, 139]), np.array([9, 176, 182]), single_meat_mask)
                ratio_well_done = get_doneness(hsv, np.array([8, 142, 136]), np.array([10, 160, 158]), single_meat_mask)

                # 推断熟度
                print(max(ratio_well_done, ratio_medium, ratio_rare, ratio_very_rare))
                li = [ratio_very_rare, ratio_rare, ratio_medium, ratio_well_done]
                # 找出最大元素的索引
                max_index = li.index(max(li))
                doneness = determine_doneness(max_index)
                doneness_results.append((x, y, doneness))
        print()
        print('--------')

        # 显示结果
        for (x, y, doneness) in doneness_results:
            # cv2.putText(frame, f"{doneness}", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2, cv2.LINE_AA)
            frame = put_chinese_text(frame, f"{doneness}", (x, y), 16, (210, 210, 210))
        cv2.imshow("Frame", frame)

        if cv2.waitKey(1000) == 27:
            break

    # cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值