扫描以上的标准模板滑动采集图像及其处理
简 介: 对于喷涂有黄色油漆的金属圆盘进行扫描。利用 滑轨带动圆盘 在 V370扫描仪 上移动,利用300dpi分辨率获得金属圆盘模板在扫描仪上不同位置和高度的图片,通过后期算法研究扫描仪在不同地方的失真以及影响测量准确性的因素。
关键词
: V370,扫描仪,cv2,HoughCircles
§01 扫描图片
1.1 喷涂黄色油漆的阴影圈
在 获取棋盘格与标准模板在扫描仪上不同位置图片 使用金属阴影圈模板在V370扫描以上进行取像的时候,由于金属表面的反射使得对应的模板图像出现亮度变化过大,会影响到后期模板圆孔面积的求取,进而使得对扫描仪的扫描精度测试产生影响。
▲ 图1.1.1 喷涂有黄色油漆的阴影圈金属模板
1.2 移动距离
根据 获取棋盘格与标准模板在扫描仪上不同位置图片 测量蜗杆滑轨的运动系数:
- 蜗杆滑轨运动系数:
-
运动步数
:3200
运动距离
:15.8cm
运动常数
:202.53 步/cm
扫描以上的金属模板移动距离:130cm。根据上面测量到的蜗杆滑轨运动系数,可以知道扫描范围的步数为: 130 × 202.53 = 2646 130 \times 202.53 = 2646 130×202.53=2646 。实际工作中定位2600。
▲ 图1.3.1 扫描以上的金属模板移动距离
1.2.1 扫描程序
from headm import *
from tsmodule.tshardware import *
'''
rcccw(2000)
exit()
'''
epson_title = 'EPSON'
save_title = '文件保存设置'
process_title = '进程'
def epsonScan():
tspsendwindowkey(epson_title, "s", alt=1,noreturn=1)
time.sleep(.1)
if sum(tspgetwindowrect(save_title)) != 0:
tspsendwindowkey(save_title, "\r", noreturn=1)
while True:
time.sleep(1)
if(sum(tspgetwindowrect(process_title)) != 0): break
tspbeep(800, 20)
while True:
time.sleep(1)
if(sum(tspgetwindowrect(process_title)) == 0): break
tspbeep(1800, 20)
printf('\a')
for i in range(50):
printf("Scan time:%d"%i)
epsonScan()
rcccw(52)
printf('\a')
1.3 扫描结果
1.3.1 水平移动扫描
▲ 图1.2.2 扫描结果
1.3.2 对角线移动扫描
▲ 图2.1 对角线方向移动
通过基于ESP8266 WiFi控制的步进升降机械平台移动固定步数,测量移动距离。
- 蜗杆平台移动参数:
-
运动步数
:2000
运动距离
:40mm
因此,每移动1mm,驱动器需要驱动50个脉冲。
驱动模块沿着对角线移动可以同时测量到扫描仪在上下以及左右方向中引起图像尺寸变化的情况。
▲ 图2.1.1 对角线移动扫描
1.3.3 上下移动扫描
使用 基于WiFi步进电机驱动单蜗杆滑轨带动阴影圈圆盘 在扫描仪上网上移动。
- 移动参数:
-
移动距离
:20mm
移动步数
:100
▲ 图3.1 上下扫描结果
§02 处理图片
2.1 检测圆形
2.1.1 利用HoughCircles检测
(1)检测程序
def modelArg(filename):
img = cv2.imread(os.path.join(filedir,filename))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1,
50, param1=220, param2=30,
minRadius=90, maxRadius=115)
return img, circles
▲ 图2.1.1 在AI Studio上处理图片
(2)结果排序
由于所检测到的四个圆圈在输出结果上并没有进行排序,因此通过下面程序对于四个结果进行排序。
def sortcircles(cc):
cca = mean(cc[0], axis=0)
angle = [math.atan2(c[1]-cca[1], c[0]-cca[0])*180/pi for c in cc[0]]
angle = [s if s >= 0 else 360+s for s in angle]
ar = sorted(zip(angle, cc[0].T[2]))
sortr = [s[1] for s in ar]
rcompare = list(array(sortr) > 100)
for i in range(3):
rc = roll(rcompare, i+1)
rsr = roll(sortr, i+1)
if rc[0] == True and rc[1] == True:
break
return rsr
▲ 图2.1.2 四个结果对应 圆圈的位置
▲ 图2.1.3 检测结果显示
2.1.2 检测结果
(1)对角线移动
▲ 图2.1.4 对角线移动测量
▲ 图2.1.5 四个圆圈测量结果
std(r1dim): 0.6596184372901917
std(r2dim): 0.5734277367591858
std(r3dim): 0.6673048138618469
std(r4dim): 0.5788406133651733
max(r1dim)-min(r1dim): 3.3000030517578125
max(r2dim)-min(r2dim): 2.5
max(r3dim)-min(r3dim): 3.6999969482421875
max(r4dim)-min(r4dim): 3.0
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# PROC1.PY -- by Dr. ZhuoQing 2022-01-25
#
# Note:
#============================================================
from headm import * # =
import cv2
from tqdm import tqdm
from tqdm import tqdm
scandiag = '/home/aistudio/work/Scanner/ScanDiag'
scanrow = '/home/aistudio/work/Scanner/ScanRow'
scanvert = '/home/aistudio/work/Scanner/ScanVert'
filedir = scanrow
filedim = sorted([s for s in os.listdir(filedir) if s.find('jpg') > 0])
#printt(filedim:)
#------------------------------------------------------------
'''
gifpath = '/home/aistudio/GIF'
if not os.path.isdir(gifpath):
os.makedirs(gifpath)
gifdim = os.listdir(gifpath)
for f in gifdim:
fn = os.path.join(gifpath, f)
if os.path.isfile(fn):
os.remove(fn)
for id,f in tqdm(enumerate(filedim)):
fn = os.path.join(filedir, f)
img = cv2.imread(fn)[:,:,::-1]
img[where(img < 50)] = 0
plt.clf()
plt.figure(figsize=(8,12))
plt.imshow(img)
savefile = os.path.join(gifpath, '%03d.jpg'%id)
plt.savefig(savefile)
'''
#------------------------------------------------------------
def modelArg(filename):
img = cv2.imread(os.path.join(filedir,filename))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1,
50, param1=150, param2=40,
minRadius=90, maxRadius=115)
# circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1,
# 50, param1=220, param2=30,
# minRadius=170, maxRadius=240)
return img, circles
#------------------------------------------------------------
def circleImg(img, cc):
for c in cc[0]:
cv2.circle(img, (int(c[0]), int(c[1])), int(c[-1]), (0,0,255), 12)
return img
#------------------------------------------------------------
def sortcircles(cc):
# printt(cc[0])
cca = mean(cc[0], axis=0)
angle = [math.atan2(c[1]-cca[1], c[0]-cca[0])*180/pi for c in cc[0]]
angle = [s if s >= 0 else 360+s for s in angle]
ar = sorted(zip(angle, cc[0].T[2]))
sortr = [s[1] for s in ar]
rcompare = list(array(sortr) > 100)
for i in range(3):
rc = roll(rcompare, i+1)
rsr = roll(sortr, i+1)
if rc[0] == True and rc[1] == True:
break
return rsr
#------------------------------------------------------------
gifpath = '/home/aistudio/GIF'
if not os.path.isdir(gifpath):
os.makedirs(gifpath)
gifdim = os.listdir(gifpath)
for f in gifdim:
fn = os.path.join(gifpath, f)
if os.path.isfile(fn):
os.remove(fn)
allcircle = []
for id,f in tqdm(enumerate(filedim)):
f = filedim[2]
img, cc = modelArg(f)
printt(cc:)
if len(cc) > 0:
img[where(img<50)] = 0
circleImg(img, cc)
r = sortcircles(cc)
allcircle.append(r)
plt.clf()
plt.figure(figsize=(8,12))
plt.imshow(img[:,:,::-1])
savefile = os.path.join(gifpath, '%03d.jpg'%id)
plt.savefig(savefile)
break
#------------------------------------------------------------
#printt(allcircle)
'''
r1dim = [c[0] for c in allcircle]
r2dim = [c[1] for c in allcircle]
r3dim = [c[2] for c in allcircle]
r4dim = [c[3] for c in allcircle]
plt.clf()
plt.figure(figsize=(12,8))
plt.plot(r1dim, label='Circle1')
plt.plot(r2dim, label='Circle2')
plt.plot(r3dim, label='Circle3')
plt.plot(r4dim, label='Circle4')
plt.xlabel("n")
plt.ylabel("Ratio")
plt.grid(True)
plt.legend(loc='upper right')
plt.tight_layout()
plt.savefig('/home/aistudio/stdout.jpg')
plt.show()
printt(std(r1dim):,std(r2dim):,std(r3dim):,std(r4dim):)
printt(max(r1dim)-min(r1dim):, max(r2dim)-min(r2dim):, max(r3dim)-min(r3dim):, max(r4dim)-min(r4dim):)
'''
#------------------------------------------------------------
# END OF FILE : PROC1.PY
#============================================================
2.2 检测精度问题
在前面处理图片过程中,由于使用了Hough算法,它在检测圆形参数的时候,精度不是很高。这是Hough算法本身的精度问题。因此需要在初步获得圆形位置的基础上,进一步提高圆形半径的检测精度。
2.2.1 采用ContourArea函数
根据前面讨论过程,为了进一步提高圆半径检测精度,可以采用OpenCV中的Contour以及ContourArea的算法,通过对图片进行分割之后,提取黑色区域的面积从而反过来计算影响半径。
2.2.2 对于边缘过渡带进行拟合
圆形的半径来自于边缘过渡带的细分,对于过渡带的灰度变化进行建模,使用上升沿的中点进行拟合来获取亚像素级别的半径。
§03 加速处理
为了提高图片的处理速度,为后面提高高性能算法,需要对图片进行预处理。
3.1 图片预分割
在测量的图片中,圆形模板仅仅占图片的一小部分,利用前面提取的模板中圆形的中心位置,将涵盖后模板的图片区域分割出来,这一方面减少了图片数据存储的空间,并未后面进行搜索和处理提高了处理速度。
3.1.1 处理程序
from headm import * # =
from tqdm import tqdm
import cv2
scandiag = '/home/aistudio/work/Scanner/ScanDiag'
scanrow = '/home/aistudio/work/Scanner/ScanRow'
scanvert = '/home/aistudio/work/Scanner/ScanVert'
scandiagblock = '/home/aistudio/work/Scanner/ScanDiagBlock'
scanrowblock = '/home/aistudio/work/Scanner/ScanRowBlock'
scanvertblock = '/home/aistudio/work/Scanner/ScanVertBlock'
filedir = scandiag
outfiledir = scandiagblock
filedim = sorted([s for s in os.listdir(filedir) if s.find("jpg") > 0])
def modelArg(filename):
img = cv2.imread(os.path.join(filedir,filename))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
bigcircle = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1,
50, param1=200, param2=60,
minRadius=530, maxRadius=580)
return img, bigcircle, bigcircle
BLOCK_SIDE2 = 600
for id,f in tqdm(enumerate(filedim)):
if id >= 0:
img,c,bc = modelArg(f)
cc = bc[0][0]
keepcc = cc
leftid = int(cc[0] - BLOCK_SIDE2)
topid = int(cc[1] - BLOCK_SIDE2)
if leftid < 0: leftid = 0
if topid < 0: topid = 0
rightid = leftid + BLOCK_SIDE2*2
bottomid = topid + BLOCK_SIDE2*2
if rightid > img.shape[1]:
rightid = img.shape[1]
leftid = rightid - BLOCK_SIDE2*2
if bottomid > img.shape[0]:
bottomid = img.shape[0]
topid = bottomid - BLOCK_SIDE2*2
blockimg = img[topid:bottomid, leftid:rightid, :]
outfile = os.path.join(outfiledir, f)
cv2.imwrite(outfile, blockimg)
3.1.2 处理结果
根据分析图片中金属图片的像素尺寸,可以看到,通过截取大圆半径5/4倍的外接正方形,将原始图像分离出来进行存储。
外轮廓的直径为1105,它的5/4对应的1381。如果截取靠近边缘,则以边缘为起始点往内延长1381,使得所有截取的存储图片的大小都是1381。
▲ 图3.1.1 对角线移动扫描结果
from headm import * # =
from tqdm import tqdm
import cv2
scandiag = '/home/aistudio/work/Scanner/ScanDiag'
scanrow = '/home/aistudio/work/Scanner/ScanRow'
scanvert = '/home/aistudio/work/Scanner/ScanVert'
scandiagblock = '/home/aistudio/work/Scanner/ScanDiagBlock'
scanrowblock = '/home/aistudio/work/Scanner/ScanRowBlock'
scanvertblock = '/home/aistudio/work/Scanner/ScanVertBlock'
filedir = scandiagblock
outfiledir = scanrowblock
filedim = sorted([s for s in os.listdir(filedir) if s.find("jpg") > 0])
gifpath = '/home/aistudio/GIF'
if not os.path.isdir(gifpath):
os.makedirs(gifpath)
gifdim = os.listdir(gifpath)
for f in gifdim:
fn = os.path.join(gifpath, f)
if os.path.isfile(fn):
os.remove(fn)
for id,f in tqdm(enumerate(filedim)):
img = cv2.imread(os.path.join(filedir, f))
img[where(img<50)] = 0
plt.clf()
plt.figure(figsize=(10,10))
plt.imshow(img[:,:,::-1])
savefile = os.path.join(gifpath, '%03d.jpg'%id)
plt.savefig(savefile)
plt.close()
▲ 图3.1.2 水平移动
▲ 图3.1.3 对角线移动
▲ 图3.1.4 垂直移动
3.2 Studio带有GPU环境
根据 AI Studio中的OpenCV在三种环境下对比 对比,在存在有GPU处理环境下,也就是在“至尊版本”中,可以获得大约五倍速度的提升。因此对于大量数据处理的时候转移到GPU环境下可以获得更快的速度。
※ 处理总结 ※
对于喷涂有黄色油漆的金属圆盘进行扫描。利用 滑轨带动圆盘 在 V370扫描仪 上移动,利用300dpi分辨率获得金属圆盘模板在扫描仪上不同位置和高度的图片,通过后期算法研究扫描仪在不同地方的失真以及影响测量准确性的因素。
■ 相关文献链接:
- 获取棋盘格与标准模板在扫描仪上不同位置图片
- 蜗杆滑轨
- 基于ESP8266 WiFi控制的步进升降机械平台
- 实验室中的第三只手:滑轨参数以及控制接口
- AI Studio中的OpenCV在三种环境下对比
- Epson Perfection V370 Photo图片扫描自动控制
● 相关图表链接:
- 图1.1.1 喷涂有黄色油漆的阴影圈金属模板
- 图1.3.1 扫描以上的金属模板移动距离
- 图1.2.2 扫描结果
- 图2.1 对角线方向移动
- 图2.1.1 对角线移动扫描
- 图3.1 上下扫描结果
- 图2.1.1 在AI Studio上处理图片
- 图2.1.2 四个结果对应 圆圈的位置
- 图2.1.3 检测结果显示
- 图2.1.4 对角线移动测量
- 图2.1.5 四个圆圈测量结果
- 图3.1.1 对角线移动扫描结果
- 图3.1.2 水平移动
- 图3.1.3 对角线移动
- 图3.1.4 垂直移动
文章来源: zhuoqing.blog.csdn.net,作者:卓晴,版权归原作者所有,如需转载,请联系作者。
原文链接:zhuoqing.blog.csdn.net/article/details/122661535
- 点赞
- 收藏
- 关注作者
评论(0)