由于工作原因,这两天要用到图片识别,第一反应是机器学习,但是现在的水平还不能够了解什么是机器学习以及如何使用机器学习的算法来解决问题,于是只能使用模板匹配来识别图片中是否包含另外一张图片。
用到的库
python 3.6
openCV
numpy
openCV-python
使用并不是很难
1.导入图片
img_rgb = cv2.imread(self.file_path) # 读取原图片
origin_w, origin_h, _ = img_rgb.shape # 获取原图大小
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY) # 转为灰色值
template = cv2.imread(self.template_image_path, 0) # 读取模板图片,注意这里第二个参数为0
w, h = template.shape[::-1] # 获取模板图片宽高
2.匹配图片
#img_gray 待匹配的图
#template 用来匹配的图
#cv2.TM_CCOEFF_NORMED 匹配的模式(我知道的有六种)
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED) # 获取匹配度[返回结果是一个二维数组]
loc = np.where(res >= 0.8)
3.标记区域 / 填充区域
template_img_loc = list(zip(*loc[::-1]))
for pt in template_img_loc:
# img_rgb 需要填充的图片
# pt 图片填充区域左上角点的坐标
# pt[0] + w + extension_right_width, pt[1] + h + extension_height 图片填充区域右下角点的坐标
# fill_color 填充颜色
# -1 填充方式 -1为填充内部(如果是2,3等正数则为填充边框的宽度)
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), fill_color, -1)
4.保存图片
cv2.imwrite(path, img_rgb)
贴一份源码:
import numpy as np
import cv2
img_path = 'xxxxx/xxxx.jpg'
img_rgb = cv2.imread(img_path)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread(img_path, 0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= 0.9)
template_img_loc = list(zip(*loc[::-1]))
for pt in template_img_loc:
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), fill_color, -1)
cv2.imwrite(path, img_rgb)
分割线
这里遇到两个版本的问题跟大家分享一下
- 之前遇到的一个,只是长时间没遇到,自己给忘了,然后又入坑
请大家注意这里:
list(zip(*loc[::-1]))
由于很多文章都是2.7的,很多文章在这里处理的时候直接使用的是zip(*loc[::-1])
但是在3.*以上之后,你不会得到一个list,而会得到一个zip对象,很奇怪,你需要用list转一下
于是就有了
list(zip(*loc[::-1]))
- 这个是我想用多进程来处理一下这个程序,单进程着实有点慢,于是我就开写了
from multiprocessing import Process, Pool, Queue, Manager, Value, Array, Lock
class ConvertImage(object):
*****
#转换文件
def convert_image(self):
lock = Manager().Lock() #创建线程锁
q = Manager().Queue() #创建队列
self.read_files_with_process(q, lock) #读取文件放入到队列中
p = Pool(processes=3) #创建进程池
#创建n个异步进程
for _ in range(3):
#func 进程执行的方法
#args 方法需要的参数
p.apply_async(func=self.execute_Q_process, args=(q,))
p.close()
p.join()
# 读取文件加下的文件 返回文件总路径保存在全局 all_files中
def read_files_with_process(self, q, lock):
for file_path in self.file_execute.read_file_paths(self.path):
*****
lock.acquire()
q.put(file_path)
lock.release()
# 执行队列进程
def execute_Q_process(self, q):
while True:
# 如果队列为空 退出循环 结束进程
if q.empty():
time.sleep(1)
# 如果等待一秒还没有数据说明已经为空 退出程序
if q.empty():
break
file_path = q.get() # 从队列中获取数据
*****
*****是我过滤掉的我认为不重要的内容
注意这里开启异步线程的时候,我们func用的是self.execute_Q_process~~~
很不巧,我遇到一个bug,将python切回了2.7,发现这里出现了问题,于是我切换成了map,提示我
# [Can't pickle <type 'instancemethod'> when using multiprocessing Pool.map()](https://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-multiprocessing-pool-map)
大概意思是我不能使用self里的方法
查了查也没有我理想的答案,但这个bug确实让我困扰了好几个小时,此处来记录一下。
网友评论