为图片绘制带箭头的坐标轴

需求说明

有时候,我们需要对一张图片进行坐标轴绘制,直观观察图片的长宽分布,并根据坐标轴中心点的选取来实现不同位置的坐标轴。
常见需求:

  • 中心点自定义
  • 坐标间隔自定义
  • 坐标轴颜色自定义
  • 透明度自定义
  • 间隔值大小自定义以及颜色自定义
  • 图片自定义

因此,本博客就以上需求进行代码实现,具体效果如下:
原图:
在这里插入图片描述
绘制坐标轴后的图:
在这里插入图片描述

实现代码

主要操作讲解都在代码中注释了,可以边看边食用

依赖的库

from matplotlib import pyplot as plt
import os

# 设置图片保存的分辨率
plt.rcParams['savefig.dpi'] = 200

主要函数

def patch_arrow(img_path, center, limits=None, interval=6, color='r', width=2, fontsize=7, fontcolor='black', alpha=0.5):
    '''
        img_path: 图片路径
        center: 中心坐标
        limits: 坐标轴间隔大小——默认为None, 表示自动求取间隔
        interval: 间隔标记的长度
        color: 坐标轴颜色
        width: 线条宽度
        fontsize: 坐标间隔的字体大小
        fontcolor: 间隔字体颜色
        alpha: 透明度--值越大,透明度越小
    '''
    # 判断输入条件是否满足基本要求
    assert os.path.isfile(img_path), \
        'please enter a truthful img_path, now it dosen`t exist.'
    assert len(center)==2, \
        'please enter center like (x, y).'
    assert alpha <= 1.0 and alpha >= 0., \
        'please enter alpha like (from 0. to 1.).'
    
    img = plt.imread(img_path)    # 读取图像
    h,w,_ = img.shape             # 获取高宽
    
    # 自动确定间隔
    auto_limit_numbers = 12  # 自动间隔点
    if limits is None:
        limits = max((h, w))
        limits = limits // auto_limit_numbers
    
    fig = plt.figure(figsize=(w/100,h/100))
    
    x, y = center[0], center[1]
    # 判断输入的中心点坐标是否超出图片区域
    assert x < w and y < h, \
        'please enter a truethful center position, which must limit in (x < w, y < h).'
    
    # 计算中心的点到图像左右两边的距离——即中心点左右两边允许的绘图区域
    to_w_left = x  
    to_w_right = (w-1) - x  # (w-1):图片布局是从0到w-1,所以x最大值为w-1
    
    # 计算中心的点到图像上下两边的距离——即中心点左右两边允许的绘图区域
    to_h_up = y
    to_h_down = (h-1) - y
    
    # 计算绘制图像时的偏移值--受限于width
    x_offset = width / 2  # 用于绘制x轴等图像时的一个偏移值,用于修正绘图
    y_offset = width / 2  # 用于修正y轴相关绘图
    
    # 展示图片
    plt.imshow(img)
    plt.axis('off') # 关闭坐标轴
    
    # 绘制x, y轴
    # 绘制x轴,保持y不变
    # 绘制y轴,保持x不变
    # head_width: 箭头大小
    # width: 线宽
    plt.arrow(x=0, y=y-y_offset, dy=0, dx=w-1, color=color, width=width, alpha=alpha, length_includes_head=True, head_width=5*width)  # x 轴
    plt.arrow(x=x-x_offset, y=h-1, dy=-h+1, dx=0, color=color, width=width, alpha=alpha, length_includes_head=True, head_width=5*width)  # y 轴
    
    # 制作x轴坐标间隔--根据limit去求解存在的间隔
    to_w_left_star = []  # 制作x轴的左轴--包含0值--即原点信息
    for i in range(0, to_w_left+1, limits):
        to_w_left_star.append(i)
    to_w_right_star = [] # 制作x轴的右轴--包含0值--即原点信息
    for i in range(0, to_w_right+1, limits):
        to_w_right_star.append(i)
        
    # 制作y轴坐标间隔
    to_h_up_star = []  # 上轴--包含0值--即原点信息
    for i in range(0, to_h_up+1, limits):
        to_h_up_star.append(i)
    to_h_down_star = []  # 下轴--包含0值--即原点信息
    for i in range(0, to_h_down+1, limits):
        to_h_down_star.append(i)
    
    # 绘制各轴的间隔
    # 之所以每一个遍历都带入一个0值判断,是为了保证循环结构的一致性,因为如果从索引1开始,当某一个轴一边不满足间隔,就会导致遍历无法进行
    for i in to_w_left_star[:]:   # x 左轴
        if i == 0:  # 跳过零点
            continue
        # 绘制坐标轴间隔线条
        plt.plot((x-i, x-i), (y-y_offset, y-y_offset-interval), color=color, alpha=alpha, linewidth=width-2 if width-2>0 else 1)
        
        # 绘制坐标轴间隔的值
        # x, y经过调整,默认参数下显示较为良好
        # 如果自定义字体过大,可能存在一定的偏移,不会很影响显示效果
        plt.text(x=x-i-0.1*limits, y=y+0.35*limits, s='{0:d}'.format(-i), fontsize=fontsize, color=fontcolor)
        
    for i in to_w_right_star[:]:  # x 右轴
        if i == 0:
            continue
        plt.plot((x+i, x+i), (y-y_offset, y-y_offset-interval), color=color, alpha=alpha, linewidth=width-2 if width-2>0 else 1)
        plt.text(x=x+i-0.1*limits, y=y+0.35*limits, s='{0:d}'.format(i), fontsize=fontsize, color=fontcolor)
    for i in to_h_up_star[:]:   # y 上轴
        if i == 0:
            continue
        plt.plot((x-x_offset, x-x_offset+interval), (y-i, y-i), color=color, alpha=alpha, linewidth=width-2 if width-2>0 else 1)
        plt.text(x=x+0.15*limits, y=y-i+0.1*limits, s='{0:d}'.format(i), fontsize=fontsize, color=fontcolor)
    for i in to_h_down_star[:]:  # y 下轴
        if i == 0:
            continue
        plt.plot((x-x_offset, x-x_offset+interval), (y+i, y+i), color=color, alpha=alpha, linewidth=width-2 if width-2>0 else 1)
        plt.text(x=x+0.15*limits, y=y+i+0.1*limits, s='{0:d}'.format(-i), fontsize=fontsize, color=fontcolor)
    
    plt.text(x=x+0.1*limits, y=y+0.35*limits, s='0', fontsize=fontsize,color=fontcolor)  # 原点标定绘制
    
    # 保存修改后的图片
    # bbox_inches='tight': 去掉白边——原坐标轴的占位
    fig.savefig('test.png',bbox_inches='tight')

示例

img_path = 'fst.jpg'  # 自行修改

# img_path: 图片路径
# center:坐标轴中心点
# limits:是否自定设置间隔--None为自动,可以自行调节大小(int/float)
# limits——设置不恰当可能出现坐标轴间隔值的重叠情况
# interval:间隔直线的高度
# color:坐标轴颜色
# width:坐标轴粗细
# fontsize:坐标轴间隔值的大小
# fontcolor:坐标轴字体颜色
# alpha:透明度
patch_arrow(img_path, center=[200, 200], limits=None, interval=12, color='r', width=3, fontsize=20, fontcolor='r', alpha=0.6)

result:
在这里插入图片描述
如果对你有帮助,不妨点赞关注一下吧!(●’◡’●)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NULL not error

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值