小团队搞算法,需要多面手,等同当个厨子要从买菜到炒菜,一直到端给顾客,还要劝顾客多吃,以便好收拾盘子。
据说,我的前辈曾是大厂的大牛,但是来了之后没出成绩,反而先要求配两个助手。后来,经过很长时间,也没有什么成绩,大牛说是助手不行,要换更高级的助手。
我听到后,我说,我不是大牛,不用助手,我喜欢从琐碎的事情中寻找规律,并开发出工具来提高效率。
图像处理,有三驾马车:硬件、样本、算法。
其中,硬件舍得花钱买就行,算法基本上对成熟的模型进行微调即可。而这个样本,却需要实打实地进行收集和标注。
比如做语义分割,你觉得,哇,真了不起,计算机那么智能,怎么就把各类物体区分出来了。
你看下面这张图,传入一张小猫的自拍照,计算机就像是能读懂图像的语义一样,轻松地把小猫、草地、森林、天空,分割了出来。
其实,它之所以智能,是因为前期喂了它很多数据。这就和养孩子一样,她叫你一声“爸爸”,你感觉好神奇,其实你仔细想想,你喂了她多少奶粉,你叫了她多少句“爸爸”。
在计算机能识别物体之前,是用了成千上万张标注好的图片进行了训练。这些图片是一个点一个点地标记了哪些像素是猫,哪些像素是草地。
而在自动驾驶领域,标注更为变态,你需要标上你看到的一切,细致到行人、非机动车、机动车、建筑物、绿植、电线、路牌、不可跨越的障碍物(如护栏)、可跨越的障碍物(如马路牙子)等等。
所以,你看到现在很多人工智能的企业招聘一种职业,叫图像标注员(可兼职,一天200)。其实,这活不好干。
市面上有很多图像样本处理工具,有做框选的labelimg,也有做标注的labelme,甚至还有人说用Photoshop。
是的,我就用过PS,是在要识别一些目标上,比如行人。需要的素材就是包含行人的图片5000张,以及不包含行人的图片1000张,这些图片要求宽高尺寸都一样。
首先,用PS打开下面的图片,然后使用裁剪工具,框出固定大小或者比例的行人,然后保存。以此类推。
这样效率很低。做了50张,我就累了。框图不累,但是输入文件名点击保存按钮等各种操作很累。
于是,我就写了下面这个工具。
它会加载文件夹下的素材图片。你只需要在图片上拉一个框出来,它就会保存这个框对应的图片。而且,起初保存的是1开头的文件名,点击鼠标右键后,保存的是0开头的文件名。这样,就可以做到先框选行人,然后再框选背景,大大地提高了效率。
以下是实现的代码,100行代码,相信结合注释,你能轻松读懂。
#%% 导入相关包
import os
import tkinter as tk
from PIL import Image
from PIL import ImageTk
import time
# 鼠标左键按下事件
def left_mouse_down(event):
global left_mouse_down_x, left_mouse_down_y
# 记录按下的坐标,赋值给全局变量
left_mouse_down_x = event.x
left_mouse_down_y = event.y
# 鼠标左键抬起事件
def left_mouse_up(event):
# 记录抬起时的坐标,鼠标左键抬起时x,y坐标
left_mouse_up_x = event.x
left_mouse_up_y = event.y
# 通过抬起的点减去按下的点,比划矩形,计算出宽和高
width = left_mouse_up_x - left_mouse_down_x
height = left_mouse_up_y - left_mouse_down_y
# 如果宽高太小,有可能是点击了一下,或者想放弃这次操作
if width < 20 or height < 20:
print("size is to small,不要了")
return
# 如果宽大于高,让高依照比例自动计算:谁幅度大听谁的
if width > height:
_height = int(width*h_scale/w_scale)
# 强行定义鼠标抬起的位置
left_mouse_up_y = left_mouse_down_y + _height
else: # 宽不大于高,一样操作
_width = int(height*w_scale/h_scale)
left_mouse_up_x = left_mouse_down_x + _width
# 保存文件
f_name = "out/"+str(crop_pos)+"_"+str(int(time.time()))+".png"
corp_image = image.crop((left_mouse_down_x, left_mouse_down_y, left_mouse_up_x, left_mouse_up_y))
corp_image.save(f_name)
# 鼠标左键按下并移动
def moving_mouse(event):
global sole_rectangle # 绘制的矩形
# 鼠标按下的x,y
global left_mouse_down_x, left_mouse_down_y
moving_mouse_x = event.x
moving_mouse_y = event.y
# 通过移动的点减去起始按下的点,比划矩形,计算出宽和高
width = moving_mouse_x - left_mouse_down_x
height = moving_mouse_y - left_mouse_down_y
if width > height:
# 如果宽大于高,让高依照比例自动计算:谁幅度大听谁的
_height = int(width*h_scale/w_scale)
# 强行定义鼠标移动的位置
moving_mouse_y = left_mouse_down_y + _height
else:
_width = int(height*w_scale/h_scale)
moving_mouse_x = left_mouse_down_x + _width
# 如果原来画过矩形,删除前一个矩形,绘制出新的
if sole_rectangle is not None:
canvas.delete(sole_rectangle)
sole_rectangle = canvas.create_rectangle(left_mouse_down_x, left_mouse_down_y, moving_mouse_x,moving_mouse_y, outline='red')
# 鼠标右键按下
def right_mouse_down(event):
pass
# 鼠标右键抬起
def right_mouse_up(event):
global crop_pos
crop_pos = 0
#%% 执行代码
if __name__ == '__main__':
# 鼠标左键按下时x,y坐标
left_mouse_down_x, left_mouse_down_y = 0, 0
sole_rectangle = None # 画出的矩形
w_scale = 1 # 画出的宽高比例
h_scale = 3
target = "img"
all_files=os.listdir(target)
for f_name in all_files:
crop_pos = 1
img_path = target+"/"+f_name
win = tk.Tk()
frame = tk.Frame()
frame.pack()
button = tk.Button(frame, text = "下一张", command=win.destroy)
button.pack()
image = Image.open(img_path)
image_x, image_y = image.size
img = ImageTk.PhotoImage(image)
canvas = tk.Canvas(frame, width=image_x, height=image_y, bg='white')
i = canvas.create_image(0, 0, anchor='nw', image=img)
canvas.pack()
canvas.bind('<Button-1>', left_mouse_down) # 鼠标左键按下
canvas.bind('<ButtonRelease-1>', left_mouse_up) # 鼠标左键释放
canvas.bind('<Button-3>', right_mouse_down) # 鼠标右键按下
canvas.bind('<ButtonRelease-3>', right_mouse_up) # 鼠标右键释放
canvas.bind('<B1-Motion>', moving_mouse) # 鼠标左键按下并移动
win.mainloop()
其逻辑有几点:
定义图像的宽高比,当鼠标拖动时,依照比例强行画出符合宽高比的矩形框,类似于PS中按着Shift+Alt等比例缩放。
还有一个小彩蛋,那就是当你下手选择图像之后,发现此位置无法裁出符合要求的图,想反悔的时候,把框缩小,此时会放弃这张图,不会保存。
阅读量:746
点赞量:0
收藏量:0