导读本文主要介绍使用python-opencv实现餐盘水果识别与计价的应用。
测试图像与说明
使用图像,拍摄环境有待改善(存在光照不均和拍摄角度的影响):
餐盘/菜品识别一般方法:
(1)识别餐盘---传统方法和机器学习/深度学习方法;
(2)识别菜品---机器学习/深度学习方法;
本文使用传统方法识别餐盘。
效果演示:
算法思路与实现步骤
思路:传统方法识别餐盘---依据颜色和形状来区分。
具体步骤:
(1)餐盘颜色共三种:白色、绿色、橙色,形状共两种:圆形和方形。区别颜色使用hsv阈值范围筛选即可,圆形与方形通过轮廓面积与轮廓最小外接圆面积的比值来筛选,圆形rate》=0.9,方形《0.9;
(2)水果共三种:苹果、香蕉、橙子,通过颜色可以区分苹果和橙子,通过轮廓最小外接矩形的宽高比可以区分香蕉和橙子;
(3)计价:盘子和水果的数量乘以对应的单价即可;
(4)设计ui,计价时显示收款码。
python-opencv实现算法核心代码与效果如下:
def recognize_dish(self,img): #-------------------香蕉检测-----------------# banana_num = 0 hsv_img=cv2.cvtcolor(img,cv2.color_bgr2hsv) lower_yellow = np.array([15,30,145])#颜色范围低阈值 upper_yellow = np.array([35,255,255])#颜色范围高阈值 mask = cv2.inrange(hsv_img,lower_yellow,upper_yellow)#根据颜色范围删选 mask = cv2.medianblur(mask, 5)#中值滤波 #cv2.imshow(‘mask_banana’, mask) contours,hierarchy = cv2.findcontours(mask, cv2.retr_external, cv2.chain_approx_none) for cnt in contours: rect = cv2.minarearect(cnt) box = cv2.boxpoints(rect) box = np.int0(box) width = max(rect[1][0],rect[1][1]) height = min(rect[1][0],rect[1][1]) center = (int(rect[0][0]),int(rect[0][1])) if width 》 180 and height 》 80 and height 《 130: #print(width,height) img = cv2.drawcontours(img,[box],0,(0,0,255),2) cv2.puttext(img,‘banana’,center,font,1,(255,0,255), 2) banana_num += 1 item_0 = qtablewidgetitem(“%d”%banana_num) self.tablewidget.setitem(8, 0, item_0)
#-------------------苹果检测-----------------# apple_num = 0 lower_apple = np.array([0,50,50])#颜色范围低阈值 upper_apple = np.array([30,255,255])#颜色范围高阈值 mask_apple = cv2.inrange(hsv_img,lower_apple,upper_apple)#根据颜色范围删选 mask_apple = cv2.medianblur(mask_apple, 9)#中值滤波 #cv2.imshow(‘mask_apple’, mask_apple) #cv2.imwrite(‘mask_apple.jpg’, mask_apple) contours2,hierarchy2 = cv2.findcontours(mask_apple, cv2.retr_external, cv2.chain_approx_none) for cnt2 in contours2: center,radius = cv2.minenclosingcircle(cnt2) area = cv2.contourarea(cnt2) #print(radius) rate = area / (math.pi * radius *radius) if radius 》 50 and radius 《 75 and rate 《 0.91: #print(radius) cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(0,255,0),2) cv2.puttext(img,‘apple’,(int(center[0]),int(center[1])),font,1,(255,0,0), 2) apple_num += 1 item_1 = qtablewidgetitem(“%d”%apple_num) self.tablewidget.setitem(6, 0, item_1)
#-------------------橘子检测-----------------# orange_num = 0 lower_orange = np.array([0,90,60])#颜色范围低阈值 upper_orange = np.array([60,255,255])#颜色范围高阈值 mask_orange = cv2.inrange(hsv_img,lower_orange,upper_orange)#根据颜色范围删选 mask_orange = cv2.medianblur(mask_orange, 5)#中值滤波 #cv2.imshow(‘mask_orange’, mask_orange) #cv2.imwrite(‘mask_orange.jpg’, mask_orange) contours3,hierarchy3 = cv2.findcontours(mask_orange, cv2.retr_external, cv2.chain_approx_none) for cnt3 in contours3: center,radius = cv2.minenclosingcircle(cnt3) area = cv2.contourarea(cnt3) #print(radius) rate = area / (math.pi * radius *radius) if radius 》 50 and radius 《 75 and rate 》 0.85: #print(radius) cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(255,0,255),2) cv2.puttext(img,‘orange’,(int(center[0]),int(center[1])),font,1,(255,255,0), 2) orange_num += 1 item_2 = qtablewidgetitem(“%d”%orange_num) self.tablewidget.setitem(7, 0, item_2)
#-------------------白色餐盘检测-----------------# white_circle_num = 0 white_rect_num = 0 lower_white = np.array([0,0,150])#颜色范围低阈值 upper_white= np.array([100,55,255])#颜色范围高阈值 mask_white = cv2.inrange(hsv_img,lower_white,upper_white)#根据颜色范围删选 mask_white = cv2.medianblur(mask_white, 5)#中值滤波 #cv2.imshow(‘mask_white’, mask_white) #cv2.imwrite(‘mask_white.jpg’, mask_white) contours4,hierarchy4 = cv2.findcontours(mask_white, cv2.retr_external, cv2.chain_approx_none) for cnt4 in contours4: area = cv2.contourarea(cnt4) center,radius = cv2.minenclosingcircle(cnt4) #print(radius) rate = area / (math.pi * radius *radius) if radius 》 100 and radius 《 160: #print(radius) if rate 》= 0.9: cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(255,255,0),2) cv2.puttext(img,‘white_circle’,(int(center[0]),int(center[1])),font,1,(0,255,0), 2) white_circle_num += 1 elif rate 》0.6 and rate 《 0.9: rect = cv2.minarearect(cnt4) box = cv2.boxpoints(rect) box = np.int0(box) #cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(255,0,255),5) img = cv2.drawcontours(img,[box],0,(255,255,0),2) cv2.puttext(img,‘white_rect’,(int(center[0]),int(center[1])),font,1,(0,255,0), 2) white_rect_num += 1 item_3 = qtablewidgetitem(“%d”%white_circle_num) self.tablewidget.setitem(0, 0, item_3) item_4 = qtablewidgetitem(“%d”%white_rect_num) self.tablewidget.setitem(1, 0, item_4)
#-------------------绿色餐盘检测-----------------# green_circle_num = 0 green_rect_num = 0 lower_green = np.array([30,65,65])#颜色范围低阈值 upper_green= np.array([80,255,255])#颜色范围高阈值 mask_green = cv2.inrange(hsv_img,lower_green,upper_green)#根据颜色范围删选 mask_green = cv2.medianblur(mask_green, 5)#中值滤波 #cv2.imshow(‘mask_green’, mask_green) #cv2.imwrite(‘mask_green.jpg’, mask_green) contours5,hierarchy5 = cv2.findcontours(mask_green, cv2.retr_external, cv2.chain_approx_none) for cnt5 in contours5: area = cv2.contourarea(cnt5) center,radius = cv2.minenclosingcircle(cnt5) #print(radius) rate = area / (math.pi * radius *radius) if radius 》 100 and radius 《 160: #print(radius) if rate 》= 0.9: cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(0,255,0),2) cv2.puttext(img,‘green_circle’,(int(center[0]),int(center[1])),font,1,(0,255,255), 2) green_circle_num += 1 elif rate 》0.6 and rate 《 0.9: rect = cv2.minarearect(cnt5) box = cv2.boxpoints(rect) box = np.int0(box) #cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(255,0,255),5) img = cv2.drawcontours(img,[box],0,(0,255,0),2) cv2.puttext(img,‘green_rect’,(int(center[0]),int(center[1])),font,1,(0,255,255), 2) green_rect_num += 1 item_5 = qtablewidgetitem(“%d”%green_circle_num) self.tablewidget.setitem(4, 0, item_5) item_6 = qtablewidgetitem(“%d”%green_rect_num) self.tablewidget.setitem(5, 0, item_6)
#-------------------橙色餐盘检测-----------------# orange_circle_num = 0 orange_rect_num = 0 lower_orange_dish = np.array([0,100,100])#颜色范围低阈值 upper_orange_dish= np.array([15,255,255])#颜色范围高阈值 mask_orange_dish = cv2.inrange(hsv_img,lower_orange_dish,upper_orange_dish)#根据颜色范围删选 mask_orange_dish = cv2.medianblur(mask_orange_dish, 5)#中值滤波 #cv2.imshow(‘mask_green’, mask_green) #cv2.imwrite(‘mask_orange_dish.jpg’, mask_orange_dish) contours6,hierarchy6 = cv2.findcontours(mask_orange_dish, cv2.retr_external, cv2.chain_approx_none) for cnt6 in contours6: area = cv2.contourarea(cnt6) center,radius = cv2.minenclosingcircle(cnt6) #print(‘----------------’) #print(radius) rate = area / (math.pi * radius *radius) if radius 》 100 and radius 《 160: #print(rate) if rate 》= 0.8: cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(0,255,0),2) cv2.puttext(img,‘orange_circle’,(int(center[0]),int(center[1])),font,1,(255,0,255), 2) orange_circle_num += 1 elif rate 》0.3 and rate 《 0.8: rect = cv2.minarearect(cnt6) box = cv2.boxpoints(rect) box = np.int0(box) #cv2.circle(img,(int(center[0]),int(center[1])),int(radius),(255,0,255),5) img = cv2.drawcontours(img,[box],0,(0,255,0),2) cv2.puttext(img,‘orange_rect’,(int(center[0]),int(center[1])),font,1,(255,0,255), 2) orange_rect_num += 1 item_7 = qtablewidgetitem(“%d”%orange_circle_num) self.tablewidget.setitem(2, 0, item_7) item_8 = qtablewidgetitem(“%d”%orange_rect_num) self.tablewidget.setitem(3, 0, item_8)
for i in range(0,9): self.tablewidget.item(i,0).settextalignment(qtcore.qt.alignhcenter|qtcore.qt.alignvcenter) self.tablewidget.item(i,1).settextalignment(qtcore.qt.alignhcenter|qtcore.qt.alignvcenter) #----------------计算价格--------------# self.price = self.price_white_circle * white_circle_num + self.price_white_rect * white_rect_num + self.price_orange_circle * orange_circle_num + self.price_orange_rect * orange_rect_num + self.price_green_circle * green_circle_num + self.price_green_rect * green_rect_num + self.price_apple * apple_num + self.price_orange * orange_num + self.price_banana * banana_num print(self.price) return img
结尾语
(1) 算法只针对水果和餐盘数量和形态较少的情形,方法供参考;
(2) 实际应用将更复杂,要求更高,一般开源的目标检测网络也很难满足要求;
(3) 常见菜品识别的实际应用要求:一个菜只用一张图片训练或做模板,训练和识别时间尽量短,能够及时更新使用。所以真正类似的产品并不好做,如果你有好的方法欢迎留言。
—版权声明—
来源: opencv与ai深度学习
仅用于学术分享,版权属于原作者。
若有侵权,请联系删除或修改!
比特币转账的手续费到底该如何计算
RFID标签读写器让工地仓库管理转向无人化、数字化
碳化硅二极管的应用领域及优势你知道吗
英飞凌寻求30亿欧元以下的收购 228亿人民币
安森美半导体推出移动医疗电子设备的系统级封装方案
如何使用Python-OpenCV实现餐盘水果识别与计价的应用
常见液压元件原理动图
联芸科技发布新Agile ECC技术,提升QLC闪充性能和使用寿命
2020年存储技术展望:AI推动数据存储理念进化
如何选择工业物联网云平台?
中国电动车发展上领先,德国技术小胜
量热法降低了 EV 转换器的功率损耗
浅谈芯片自热问题
海康威视运用智能物联技术与产品为江夏构建多项智慧农业应用
恩智浦推出一款低成本芯片GreenChip TEA1733
OPPOR11什么时候上市?OPPOR11最新消息:OPPOR11骁龙660+4GB运存+2900mAh,OPPOR11人像模式解析
体感控制渐成主流 MEMS传感器市场迅速升温
中国电信坚持SA方向,力争在2020年启动面向5G SA的网络升级
新iphone SE挺良心,兼具强悍性能的惟一小尺寸机型
Ecosia已成Brave浏览器引擎的提供商