导读

本文主要介绍使用Python-OpenCV实现餐盘水果识别与计价的应用。

测试图像与说明

使用图像如下,拍摄环境有待改善(存在光照不均和拍摄角度的影响):

餐盘/菜品识别一般方法:

(1)识别餐盘---传统方法和机器学习/深度学习方法;

(2)识别菜品---机器学习/深度学习方法;

本文使用传统方法识别餐盘。

效果演示:

Python OpenCV 餐盘识别水果识别小应用

算法思路与实现步骤

思路:传统方法识别餐盘---依据颜色和形状来区分。

具体步骤:

(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实现餐盘水果识别计价程序(附代码)相关推荐

  1. 独家 | 手把手教你从有限的数据样本中发掘价值(附代码)

    作者:Bety Rodriguez-Milla 翻译:和中华 校对:吴金笛 本文约2800字,建议阅读8分钟. 本文展示了当数据稀缺时,如何一步步进行分析从而得到一些见解. [ 导读 ]本文是系列文章 ...

  2. 手把手教你在多种无监督聚类算法实现Python(附代码)

    来源: 机器之心 本文约2704字,建议阅读6分钟. 本文简要介绍了多种无监督学习算法的 Python 实现,包括 K 均值聚类.层次聚类.t-SNE 聚类.DBSCAN 聚类. 无监督学习是一类用于 ...

  3. 手把手教你如何自己设计实现一个深度学习框架(附代码实现)

    作者丨王桂波@知乎(已授权) 来源丨https://zhuanlan.zhihu.com/p/78713744 编辑丨极市平台 导读 本文首先从深度学习的流程开始分析,对神经网络中的关键组件抽象,确定 ...

  4. 实例 :教你使用简单神经网络和LSTM进行时间序列预测(附代码)

    翻译:张玲  校对:丁楠雅 本文约1500字,建议阅读5分钟. 作者基于波动性标准普尔500数据集和Keras深度学习网络框架,利用python代码演示RNN和LSTM RNN的构建过程,便于你快速搭 ...

  5. 实战六:手把手教你用TensorFlow进行手写数字识别

    手把手教你用TensorFlow进行手写数字识别 github下载地址 目录 手写体数字MNIST数据集介绍 MNIST Softmax网络介绍 实战MNIST Softmax网络 MNIST CNN ...

  6. linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  7. linux 进程间通信 dbus-glib【实例】详解二(上) 消息和消息总线(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  8. python模块cv2人脸识别_手把手教你使用OpenCV,Python和深度学习进行人脸识别

    使用OpenCV,Python和深度学习进行人脸识别 在本教程中,你将学习如何使用OpenCV,Python和深度学习进行面部识别.首先,我们将简要讨论基于深度学习的面部识别,包括"深度度量 ...

  9. Blender图解教程:手把手教你做马里奥问号箱 二 强迫症修复版(附模型下载)

    看完 <Blender图解教程:手把手教你做马里奥问号箱>有强迫症同学反应对最后的结果不能忍.那么老王教大家修复一下.初学的同学可以通过这个例子进一步理解一下什么是UV. 修复前 如果你没 ...

  10. 独家 | 手把手教你使用OpenCV库(附实例、Python代码解析)

    作者:Anirudh Rao 翻译:吴金笛 校对:李洁 本文约4000字,建议阅读10+分钟. 本文将通过几个简单的实例带你上手OpenCV库,新手必备!

最新文章

  1. servlet config 初始化参数
  2. 网络技术温故知新(一)
  3. 20172303 2017-2018-2 《程序设计与数据结构》第4周学习总结
  4. 使用JUnit 5 执行条件和并发测试
  5. 用JavaScript实现的设计模式之commandline(命令行)模式
  6. cdi 2.7.5_集成测试CDI 1.0和Spring 3.1中的作用域bean
  7. NOIP2017(不算是题解)
  8. 神经网络识别车牌字符
  9. httpservletrequest 设置请求头_大部分程序员不知道的 Servelt3 异步请求,原来这么简单?
  10. python是什么类型的编程语言-Python是个什么语言?
  11. centos6 与 7 其中的一些区别
  12. python 安居客 爬虫_Python爬虫安居客房价信息(并利用百度地图API查询坐标)
  13. linux 系统中没有rpm命令
  14. 基于JavaWeb网上商城(以卖书为主)
  15. 使用css画出一条虚线
  16. Qt下载安装教程,windows10亲测可用,版本5.12.11
  17. RabbitMQ 四种类型发送接收数据方式
  18. 8in1模拟器v2模拟飞行_重新想象飞行模拟器:过去和现在
  19. Invalid bound statement (not found): cn.jeefast.xiangmu.dao.AchDao.selectByI 解决
  20. Java开发在线报名系统_单独招生在线报名系统设计和实现.doc

热门文章

  1. Vue电影网站构建实战教程
  2. 移动跨平台框架React Native 基础教程【01】
  3. 安卓平台模拟软件绑定的手机(号码)以及地理位置
  4. ai杀手级_设计师的10个杀手级Adobe Photoshop技巧
  5. 求职面试中如何做好自我介绍?
  6. 如何准备全国计算机二级Python,二级Python考试技巧
  7. 【旅行】2月17日 南京 - 日照 451公里自驾过年
  8. 高一计算机函数公式,高一函数公式汇总
  9. 【LLVM实践】死循环插桩检测
  10. 项目实训 : gitlab 配置ssh key后不生效问题