识别cavans中的横坐标间距

这个Python类`ImageTrace`用于从图表图片中自动检测横坐标轴的间距。它首先处理图片,然后通过查找白色背景上的非白色像素点来识别可能的数据点。在找到足够的数据点组后,计算并返回满足最小间距要求的横坐标间距。适用于数据分析和自动化报告生成的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import os.path
import traceback

from typing import List,Tuple
from PIL import Image


class ImageTrace:
    '''
    :returns 通过cavans图获取图表横坐标的间距
    '''
    def __init__(self, png: 'str filename',min_group=2,radius=5,minx_space=20,crops:Tuple=False):
        '''
        :param png:
        :param crops: (left, upper)
        :param min_group: 最小组数,指代该图表中的数据类别数量,尽量不小于2
        :param radius: 数据与坐标轴的交点,圆的半径
        :param minx_space: 最小间距,默认为20
        '''
        self.__ps = 'other.png'
        tmp=Image.open(png)
        # draw=ImageDraw.ImageDraw(tmp)
        # draw.line([(120, 0), (120, 1302)], fill=(0, 255, 255), width=2)
        # draw.line([(0, 70), (2560, 70)], fill=(0, 255, 255), width=2)
        # tmp.show()
        if crops:
            tmp=tmp.crop((*crops,*tmp.size))
        tmp.convert('L').save(self.__ps)
        self._im = Image.open(self.__ps)
        self.min_group, self.radius,self.minx_space=\
            min_group,radius,minx_space

    def __call__(self):
        return self.parse_space(
                                self.get_space(self.min_group,self.radius),
                                self.minx_space
                                )

    def get_space(self, min_group=2, radius=5) -> List:
        width, height = self._im.size
        im = self._im.convert('RGB')
        img_obj = im.load()
        ws = []
        for w in range(width):  # 先x轴在y轴方向遍历每一个点
            cicle = []
            for h in range(height):
                rgb = im.getpixel((w, h))
                if rgb == (255, 255, 255):
                    down_hs = set()
                    up_hs = set()
                    for tmp_h1 in range(h - radius, h):
                        color = img_obj[w, tmp_h1]
                        if color != (255, 255, 255) and color != (0, 0, 0):
                            down_hs.add((w, h, color))
                    for tmp_h2 in range(h, h + radius):
                        color = img_obj[w, tmp_h2]
                        if color != (255, 255, 255) and color != (0, 0, 0):
                            up_hs.add((w, h, color))
                    # print(down_hs,up_hs)
                    if up_hs.intersection(down_hs):
                        cicle.append(w)
            if len(cicle) >= min_group * 2:
                # print(cicle)
                ws.append(cicle[0])
        return ws

    def parse_space(self, ws, minx_space=20):
        '''
        :param ws:
        :param minx_space: 最小间距
        :return:
        '''
        res_ws = []
        for index, x in enumerate(ws[:-1]):  # 清理小于最小间距的点
            if x + minx_space < ws[index + 1]:
                res_ws.append(x)
        res_ws.append(ws[-1])
        d = (res_ws[-1] - res_ws[0]) // (len(res_ws) - 1)
        d = self._depth_parse(res_ws, d)
        return d

    def _depth_parse(self, ws, d):
        rs = []
        ds=[]
        # print(ws,d)
        for i, w in enumerate(ws):
            if i < len(ws) - 1:
                rs.append(ws[i + 1] - w)
        rs.sort(reverse=True)
        for index,r in enumerate(rs):
            if r>=d:
                ds.append(r)
        return sum(ds)//len(ds)

    def __del__(self):
        try:
            if os.path.exists(self.__ps):
                os.remove(self.__ps)
        except:
            traceback.print_exc()


if __name__ == '__main__':
    img = ImageTrace('test.png',crops=(120,70))
    print(img())
import os.path
import traceback

from typing import List,Tuple
from PIL import Image


class ImageTrace:
    '''
    :returns 通过cavans图获取图表横坐标的间距
    '''
    def __init__(self, png: 'str filename',min_group=2,radius=5,minx_space=20,crops:Tuple=False):
        '''
        :param png:
        :param crops: (left, upper)
        :param min_group: 最小组数,指代该图表中的数据类别数量,尽量不小于2
        :param radius: 数据与坐标轴的交点,圆的半径
        :param minx_space: 最小间距,默认为20
        '''
        self.__ps = 'other.png'
        tmp=Image.open(png)
        # draw=ImageDraw.ImageDraw(tmp)
        # draw.line([(120, 0), (120, 1302)], fill=(0, 255, 255), width=2)
        # draw.line([(0, 70), (2560, 70)], fill=(0, 255, 255), width=2)
        # tmp.show()
        if crops:
            tmp=tmp.crop((*crops,*tmp.size))
        tmp.convert('L').save(self.__ps)
        self._im = Image.open(self.__ps)
        self.min_group, self.radius,self.minx_space=\
            min_group,radius,minx_space

    def __call__(self):
        return self.parse_space(
                                self.get_space(self.min_group,self.radius),
                                self.minx_space
                                )

    def get_space(self, min_group=2, radius=5) -> List:
        width, height = self._im.size
        im = self._im.convert('RGB')
        img_obj = im.load()
        ws = []
        for w in range(width):  # 先x轴在y轴方向遍历每一个点
            cicle = []
            for h in range(height):
                rgb = im.getpixel((w, h))
                if rgb == (255, 255, 255):
                    down_hs = set()
                    up_hs = set()
                    for tmp_h1 in range(h - radius, h):
                        color = img_obj[w, tmp_h1]
                        if color != (255, 255, 255) and color != (0, 0, 0):
                            down_hs.add((w, h, color))
                    for tmp_h2 in range(h, h + radius):
                        color = img_obj[w, tmp_h2]
                        if color != (255, 255, 255) and color != (0, 0, 0):
                            up_hs.add((w, h, color))
                    # print(down_hs,up_hs)
                    if up_hs.intersection(down_hs):
                        cicle.append(w)
            if len(cicle) >= min_group * 2:
                # print(cicle)
                ws.append(cicle[0])
        return ws

    def parse_space(self, ws, minx_space=20):
        '''
        :param ws:
        :param minx_space: 最小间距
        :return:
        '''
        res_ws = []
        for index, x in enumerate(ws[:-1]):  # 清理小于最小间距的点
            if x + minx_space < ws[index + 1]:
                res_ws.append(x)
        res_ws.append(ws[-1])
        d = (res_ws[-1] - res_ws[0]) // (len(res_ws) - 1)
        d = self._depth_parse(res_ws, d)
        return d

    def _depth_parse(self, ws, d):
        rs = []
        ds=[]
        # print(ws,d)
        for i, w in enumerate(ws):
            if i < len(ws) - 1:
                rs.append(ws[i + 1] - w)
        rs.sort(reverse=True)
        for index,r in enumerate(rs):
            if r>=d:
                ds.append(r)
        return sum(ds)//len(ds)

    def __del__(self):
        try:
            if os.path.exists(self.__ps):
                os.remove(self.__ps)
        except:
            traceback.print_exc()


if __name__ == '__main__':
    img = ImageTrace('test.png',crops=(120,70))
    print(img())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值