解决:我们选择以HSV来做颜色的追踪,以抓取红框杂讯为主。
解决:采取将图片灰阶的方法,就没有颜色的影响。
HSV(Hue, Saturation, Value)
HSV+OpenCV
# 将RGB转换成HSV颜色空间
redhsv1 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
转换成HSV後就可以来将特定的颜色找出来,助於我们找出红框的颜色,加以去除。
首先,我们需要用到HSV的调色盘,才抓到图档每个点的值是多少。以下图为例,我点选左右两点的红线,他则可以显示出我们需要的HSV值为多少。
import cv2
import numpy as np
# 读取中文路径图档(图片读取为BGR)
def cv_imread(filePath):
cv_img = cv2.imdecode(np.fromfile(filePath, dtype=np.uint8), -1)
return cv_img
# 点击欲判定HSV值的图片位置(以滑鼠左键单击)
def mouse_click(event, x, y, flags, para):
if event == cv2.EVENT_LBUTTONDOWN:
print("BGR:", img[y, x])
print("GRAY:", gray[y, x])
print("HSV:", hsv[y, x])
print('='*30)
if __name__ == '__main__':
# 读取图档
img = cv_imread('./pic/1_经.jpg')
img = cv2.resize(img, (320, 240))
# 转换成gray与HSV
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.namedWindow("img")
cv2.setMouseCallback("img", mouse_click)
while True:
cv2.imshow('img', img)
if cv2.waitKey() == ord('q'):
break
cv2.destroyAllWindows()
透过这样点选的方式,可以找出红线的值,我们就可以将它取出。我们先锁定红线,慢慢的点,大概有个阈值出来。下列程序码为追踪红线。
def red1_mask(img):
#红1
lower = np.array([150,80,94])
upper = np.array([180,255,255])
redhsv1 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask1 = cv2.inRange(redhsv1, lower, upper)
return mask1
白色是我们追踪到的红线部分,发现右边还有些红线尚未被追踪到。
於是我们要试着把右边红线的部分,看能否追踪到多一点。依照上述步骤继续点选红线位置,找出他的阈值,下列程序码为追踪第二段红线。
def red2_mask(img):
#红2
lower = np.array([0,80,89])
upper = np.array([10,255,255])
redhsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(redhsv, lower, upper)
return mask
可以发现我们追踪到上面没追踪到的红色部分,还缺少最右边的红色线条,因为他有跟中文字重叠。
接下来我们将追踪到的两个红色线条合起来。
#红1
mask1 = red1_mask(img)
#红2
mask2 = red2_mask(img)
#红1 + 红2 范围
mask3 = cv2.bitwise_or(mask1,mask2)
透过bitwise_or取联集,使两张图合并在一起。
取出红线之後,我们需要将他去除掉,也就是用背景颜色去填补,在这之前我们先将他膨胀,然後白色的地方转成黑色的。
def my_dilate(img):
kernel = np.ones((3, 3), np.uint8)
new_img = cv2.dilate(img, kernel, iterations=1)
return new_img
# 膨胀mask3
mask3 = my_dilate(mask3)
#黑白反转
mask3 = cv2.bitwise_not(mask3,mask3)
黑框是特别截图下来,以示整张图片,主要是白色变黑色。
先做一个动作,将原本的图片做灰阶,再来就是黑色部份我们到时候要用背景颜色来填补,所以我们要取出最常出现的颜色,也就是取众数。以下程序码。
def get_mode(img):
##阈值取众数
# bincount():统计非负整数的个数,不能统计浮点数
counts = np.bincount(img.flatten())
#counts的index代表出现的数,counts[index]代表出现数的次数
#今要求counts[index] 排序後最大跟第二大的counts的index(代表众数跟出现第二多次的数)
counts_sort = np.argsort(counts) #最後一个元素是counts最大值的index ,倒数第二是二大
index = counts_sort[-1]
#以防图片出现大量黑色面积
if index <= 100: #出现大量黑色区块的话,取第二多数
print('index2:',index)
index = counts_sort[-2]
return index
#否则就return原本的众数
print('index_org',index)
return index
image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
image_mode =get_mode(image)
#把红色的mask区域换成众数
image[mask3==0]= image_mode
这样我们就成功把红线的杂讯去除了。
这边图片还是有点模糊,我们做了高斯滤波,让图片较平滑,左边是原图,右边是高斯滤波过後的图,可以看出较平滑。
blur = cv2.GaussianBlur(image,(3,3),0)
这边当时遇到了小问题,当时在选择灰阶和二质化的图档做训练的时候,两种我们都有尝试过,但後来发现灰阶的资讯较多,所以我们选择用灰阶的方式去训练图片。
二质化 灰阶
import os
import random
import shutil
import os
import shutil
# 分成训练集跟资料集
src_dir_name = './train/'
target_dir_name = './test/'
test_size = 0.3
labels = set(os.listdir(src_dir_name))
def word_classfier():
word_list_dir = []
for i in os.listdir(src_dir_name):
if i.endswith('.jpg'):
word_list_dir.append(i.split('.')[0][-1])
word_list_dir = set(word_list_dir)
print(word_list_dir)
for i in os.listdir(src_dir_name):
if i.endswith('.jpg'):
if i.split('.')[0][-1] in word_list_dir:
try:
os.mkdir(src_dir_name+i.split('.')[0][-1])
except FileExistsError:
pass
shutil.move(src_dir_name+i,src_dir_name+i.split('.')[0][-1]+'/'+i)
def move_test_data(test_data:list):
for i in test_data:
word_subfolder = i.split('.')[0][-1]
if word_subfolder in labels:
print(src_dir_name+word_subfolder+'/'+i)
try:
os.mkdir(target_dir_name +word_subfolder)
except FileExistsError:
pass
shutil.move(src_dir_name+word_subfolder+'/'+i,target_dir_name +word_subfolder+'/'+i)
elif word_subfolder not in labels:
word_subfolder = i.split('.')[0][0]
print(src_dir_name+word_subfolder+'/'+i)
try:
os.mkdir(target_dir_name +word_subfolder)
except FileExistsError:
pass
try:
shutil.move(src_dir_name+word_subfolder+'/'+i,target_dir_name +word_subfolder+'/'+i)
except FileNotFoundError:
shutil.move(src_dir_name + word_subfolder + '/' + i, target_dir_name + word_subfolder + '/' + i)
def test_train_split():
try:
os.mkdir(target_dir_name)
except FileExistsError:
pass
for i in os.listdir(src_dir_name):
#每个字的照片数
dir_length = len(os.listdir(src_dir_name+i))
#3:7抽样
test_size = round(0.3 * dir_length)
test_data = random.sample(os.listdir(src_dir_name+i), k=test_size)
move_test_data(test_data)
if __name__ == '__main__':
# 把字分类成800个资料夹
word_classfier()
# 分成训练集跟测试集
test_train_split()
>>: Day15 Vue directives(v-for)下
大家好~ 我是五岁~ 今天来继续改善昨天的九尾狐草图吧~ 首先把耳朵厚度加厚了,并且加上毛茸茸的前饰...
翻翻卡 ( 卡牌记忆 ) 教学原文参考:翻翻卡 ( 卡牌记忆 ) 这篇文章会介绍,如何在 Scrat...
到目前为止的范例都是只有单一类别,但在真实的世界里其实是更复杂的,像是如果想要再加入一个小狗类别: ...
感觉经历了一段乱流区,我走到柜台,跟太子点了杯冰咖啡,就在等咖啡的时候,门打开了,看到一个身影,坐到...
Q: 动画影片看起来卡卡的? A: 请各位见谅,跑起来真真是顺畅的呢! 上一篇的Slot效果以父层...