@ALL 这是对原始问题的编辑,以使该主题更加清晰。
问题陈述
- 假设有一个工业 P&ID 图。
- 旨在仅对过程重要的一些线条着色。
- 用户只应单击(鼠标左键单击)线段以使其着色。
问题方法
我是编程新手-> 使用 Python (3.5) 来尝试一下。我看到它的算法是这样的:
- 该图将采用 .pdf 格式。因此,我可以使用 PIL ImageGrab 或将 .pdf 转换为 .png,如本例所示
- 该算法将搜索鼠标单击周围的像素,然后将其与相同大小的另一部分(假设是 6x3 像素的条带)进行比较,但向左/向右一步(可能是 1-5 像素)
- 检查它们差异的平均值将告诉我们两条条带是否相同
- 这样算法应该找到行尾、箭头、角或其他元素
- 一旦找到,记录位置并绘制标记线,用户应该选择另一条线
总结
- 点击想要的线路
- 围绕鼠标单击抓取图像的一小部分
- 检查线条是水平的还是垂直的
- 裁剪给定大小的水平/垂直切片
- 查找行尾并记录行尾位置
- 在两个找到的位置之间画一条特定颜色的线(比如说绿色)
- 等待下一行被选中并重复
其他想法
- 附上您可以找到两张示例图像的图片以及我想要实现的目标。
- 尝试使用此处找到的方法在切片中找到“洞”:OpenCV to find line endings
- 坚持 ImageGrab 例程或类似的东西没有严格的规定
- 如果您知道我可以使用的其他策略,请随时发表评论
- 欢迎任何建议并真诚感谢
示例图片:
期望的结果(在 Paint 中修改):
使用我迄今为止尝试过的工作为帖子添加更新
我对原始代码做了一些修改,所以我将在下面发布。注释中的所有内容要么用于调试,要么用于解释。非常感谢您的帮助!不要害怕干预。
import win32gui as w
from PIL import ImageStat, ImageChops, Image, ImageDraw
import win32api as wa
img=Image.open("Trials.jpg")
img_width=img.size[0]
img_height=img.size[1]
#Using 1920 x 1080 resolution
#Hide the taskbar to center the Photo Viewer
#Defining a way to make sure the mouse click is inside the image
#Substract the width from total and divide by 2 to get base point of the crop
width_lim = (1920 - img_width)/2
height_lim = (1080 - img_height)/2-7
#After several tests, the math in calculating the height is off by 7 pixels, hence the correction
#Use these values when doing the crop
#Check if left mouse button was pressed and record its position
left_p = wa.GetKeyState(0x01)
#print(left_p)
while True :
a=wa.GetKeyState(0x01)
if a != left_p:
left_p = a
if a<0 :
pos = w.GetCursorPos()
pos_x=pos[0]-width_lim
pos_y=pos[1]-height_lim
# print(pos_x,pos_y)
else:
break
#img.show()
#print(img.size)
#Define the crop height; size is doubled
height_size = 10
#Define max length limit
#Getting a horizontal strip
im_hor = img.crop(box=[0, pos_y-height_size, img_width, pos_y+height_size])
#im_hor.show()
#failed in trying crop a small square of 3x3 size using the pos_x
#sq_size = 3
#st_sq = im_hor.crop(box=[pos_x,0,pos_x+sq_size,height_size*2])
#st_sq.show()
#going back to the code it works
#crop a standard strip and compare with a new test one
#if the mean of difference is zero, the strips are identical
#still looking for a way to find the position of the central pixel (that would be the one with maximum value - black)
strip_len = 3
step = 3
i = pos_x
st_sq = im_hor.crop(box=[i,0,i+strip_len,height_size*2])
test_sq = im_hor.crop(box=[i+step,0,i+strip_len+step,height_size*2])
diff = ImageChops.difference(st_sq,test_sq)
stat=ImageStat.Stat(diff)
mean = stat.mean
mean1 = stat.mean
#print(mean)
#iterate to the right until finding a different strip, record position
while mean==[0,0,0]:
i = i+1
st_sq = im_hor.crop(box=[i,0,i+strip_len,height_size*2])
#st_sq.show()
test_sq = im_hor.crop(box=[i+step,0,i+strip_len+step,height_size*2])
#test_sq.show()
diff = ImageChops.difference(st_sq,test_sq)
#diff.show()
stat=ImageStat.Stat(diff)
mean = stat.mean
# print(mean)
print(i-1)
r = i-1
#print("STOP")
#print(r)
#record the right end as r = i-1
#iterate to the left until finding a different strip. record the position
while mean1==[0,0,0]:
i = i-1
st_sq = im_hor.crop(box=[i,0,i+strip_len,height_size*2])
#st_sq.show()
test_sq = im_hor.crop(box=[i+step,0,i+strip_len+step,height_size*2])
#test_sq.show()
diff = ImageChops.difference(st_sq,test_sq)
#diff.show()
stat=ImageStat.Stat(diff)
mean1 = stat.mean
# print(mean)
#print("STOP")
print(i+1)
l = i+1
#record the left end as l=i+1
test_draw = ImageDraw.Draw(img)
test_draw.line([l,pos_y,r,pos_y], fill=128)
img.show()
#find another approach or die trying!!!
下面是我得到的结果。这不是我所希望的,但我觉得自己走在了正确的轨道上。我真的可以使用一些帮助来查找条带中的像素位置并使其相对于大图片像素位置。
另一个类似的图像,质量更好,但也带来了更多的问题。