我们经常在论文中会看到下面这些样式的图片:在图片中使用矩形框框出感兴趣的区域,然后在底部或者其他位置附上对应的局部放大的细节图,简洁好看。✨
曾尝试使用过PPT制作,也能得到类似的效果,但是比较费时间,最关键的是如果要在两张图片中放大同一个位置的细节的话,很难定位到同一个区域。
因此,想到使用python来画这种图,可以简单实现这种好看的科研绘图了。大家如果有更便捷的方式,欢迎分享。
注意几个地方:
画图
软件得到,鼠标移动时可以实时显示像素的坐标。但是这里更推荐使用下面这个网站获取坐标,它实际上是用来制作数据集的一个网站,不过这里拿来使用获取坐标也非常适合,因为chu可以实时显示鼠标所在像素的坐标以外,还可以显示矩形框的区域。代码:
import cv2
import numpy as np
imgpath = r'56.png'
image = cv2.imdecode(np.fromfile(imgpath, dtype=np.uint8), cv2.IMREAD_COLOR)
# 放大图位置
a = (608,303) #矩形框左上角坐标
b = (657,331) #矩形框右下角坐标
lw = 2 # 矩形框线条宽度
# 截出放大的部分
img_magnify = image[a[1]-lw:b[1]+lw,a[0]-lw:b[0]+lw,:]
# 计算缩放比例
new_W = image.shape[1] - 2*lw
ratio = float(new_W) / img_magnify.shape[1]
# 根据缩放比例计算缩放后的尺寸
new_height = int(img_magnify.shape[0] * ratio)
new_size = (new_W,new_height)
# 进行缩放
resized_image = cv2.resize(img_magnify, new_size)
# 添加边框
border_size = lw
border_color = (0, 0, 255) # 红色
resized_image = cv2.copyMakeBorder(resized_image, border_size, border_size, border_size, border_size, cv2.BORDER_CONSTANT, value=border_color)
# 画矩形框
cv2.rectangle(image, a, b, (0, 0, 255), lw)
# 拼接
patch = np.vstack((image, resized_image))
cv2.imshow('1',patch)
cv2.waitKey(0)
cv2.imwrite('E:/rec_56.png',patch)
上面步骤好像还是有点麻烦,不妨把获取坐标这一步骤也用python来实现,而且希望是一次性绘制两张图片的局部放大图。
import cv2
import numpy as np
def save_magnify(path,a,b): # a:矩形框左上角坐标 ; b:矩形框右下角坐标
imagee = cv2.imread(path)
lw = 2
# 截出放大的部分
img_magnify = imagee[a[1]-lw:b[1]+lw,a[0]-lw:b[0]+lw,:]
# 计算缩放比例
new_W = imagee.shape[1] - 2*lw
ratio = float(new_W) / img_magnify.shape[1]
# 根据缩放比例计算缩放后的尺寸
new_height = int(img_magnify.shape[0] * ratio)
new_size = (new_W,new_height)
# 进行缩放
resized_image = cv2.resize(img_magnify, new_size)
# 添加边框
border_size = lw
border_color = (0, 0, 255) # 红色
resized_image = cv2.copyMakeBorder(resized_image, border_size, border_size, border_size, border_size, cv2.BORDER_CONSTANT, value=border_color)
# 画矩形框
cv2.rectangle(imagee, a, b, (0, 0, 255), lw)
# 拼接
patch = np.vstack((imagee, resized_image))
cv2.imshow(path.split('\\')[-1],patch)
cv2.waitKey(0)
# cv2.imwrite("E:\png_jpg"+ '/' + path.split('\\')[-1],patch)
# 全局变量
drawing = False # 是否正在绘制矩形框
start_x, start_y = -1, -1 # 矩形框左上角坐标
end_x, end_y = -1, -1 # 矩形框右下角坐标
def draw_rectangle(event, x, y, flags, param):
global drawing, start_x, start_y, end_x, end_y
if event == cv2.EVENT_LBUTTONDOWN: # 左键击下
drawing = True
start_x, start_y = x, y
elif event == cv2.EVENT_LBUTTONUP: # 左键弹起
drawing = False
end_x, end_y = x, y
if drawing:
# 绘制矩形框
image_copy = image.copy()
cv2.rectangle(image_copy, (start_x, start_y), (x, y), (0, 0, 255), 2)
cv2.imshow("Image", image_copy)
if not drawing and start_x != -1 and start_y != -1:
# 显示矩形框的左上角和右下角坐标
print(f"矩形框左上角坐标:({start_x}, {start_y})")
print(f"矩形框右下角坐标:({end_x}, {end_y})")
for i in range(1):
save_magnify(image_path,a = (start_x,start_y),b = (end_x,end_y))
save_magnify(image_path_2,a = (start_x,start_y),b = (end_x,end_y))
break
start_x = -1
if __name__ == '__main__':
# 输入图像路径
image_path = r'F:\Picture\a1.jpg'
image_path_2 = r'F:\Picture\a2.jpg'
# 读取图像
global imagee
image = cv2.imread(image_path)
# 创建窗口并显示图像
cv2.namedWindow("Image")
cv2.imshow("Image", image)
# 设置鼠标回调函数
cv2.setMouseCallback("Image", draw_rectangle)
# 循环等待按键事件
while True:
key = cv2.waitKey(1) & 0xFF
# 按下 'q' 键 或者 退出窗口时 退出程序
if key == ord('w') or cv2.getWindowProperty("Image", cv2.WND_PROP_VISIBLE) < 1:
break
cv2.destroyAllWindows()
save_magnify
最后一句取消注释即可。2.0版基本可以实现所需要的功能,不过代码也存在一些问题,后续再进行改进。
另外,这里还有好多功能没有来得及实现,例如对放大区域和原图之间的距离的调节、对一张图片中多个区域放大并显示、矩形框颜色、线框等自定义设置等,希望后面有时间给出3.0、4.0版。