论文绘图——局部细节放大

文章目录

  • 前言
  • 一、绘图1.0版
  • 二、绘图2.0版
  • 三、总结


前言

我们经常在论文中会看到下面这些样式的图片:在图片中使用矩形框框出感兴趣的区域,然后在底部或者其他位置附上对应的局部放大的细节图,简洁好看。✨
曾尝试使用过PPT制作,也能得到类似的效果,但是比较费时间,最关键的是如果要在两张图片中放大同一个位置的细节的话,很难定位到同一个区域
因此,想到使用python来画这种图,可以简单实现这种好看的科研绘图了。大家如果有更便捷的方式,欢迎分享。



一、绘图1.0版

  • 思路:实现步骤非常简单:
获取放大区域的左上角和右下角的像素坐标
加框并截出区域
放大至和原图等宽/等高
加上边框
  • 注意几个地方:

    • 获取左上和右下坐标可以使用画图软件得到,鼠标移动时可以实时显示像素的坐标。但是这里更推荐使用下面这个网站获取坐标,它实际上是用来制作数据集的一个网站,不过这里拿来使用获取坐标也非常适合,因为chu可以实时显示鼠标所在像素的坐标以外,还可以显示矩形框的区域。
      https://www.makesense.ai/
    • 放大到和原图等宽/高时,注意要给矩形框的线宽留一部分空余(其实就是放大到原图的宽度减去2倍的矩形框的线宽),而且不能先给放大的区域加上矩形框然后再放大,这样的话,矩形框的线框也会被放大,影响最终视图效果。
  • 代码:

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)
  • 效果:

二、绘图2.0版

上面步骤好像还是有点麻烦,不妨把获取坐标这一步骤也用python来实现,而且希望是一次性绘制两张图片的局部放大图。
  • 在1.0的基础上加上利用鼠标回调函数实现即可,直接看代码:
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()
  • 演示效果:
    运行后框出需要放大的区域,得到第一张图片,然后按下除了“w”的任意键,会得到第二张图片,最终退出程序。如果需要保存图片, 可以将save_magnify 最后一句取消注释即可。

三、总结

2.0版基本可以实现所需要的功能,不过代码也存在一些问题,后续再进行改进。

另外,这里还有好多功能没有来得及实现,例如对放大区域和原图之间的距离的调节、对一张图片中多个区域放大并显示、矩形框颜色、线框等自定义设置等,希望后面有时间给出3.0、4.0版。‍

你可能感兴趣的:(python,科研绘图,画图)