python 实现统计图像上的椭圆(ellipse) 内的信息

本文介绍如何使用Python高效地计算图像上指定椭圆区域的像素信息,包括获取椭圆参数、计算bounding box、判断点在椭圆内,并提供了一个具体的应用示例。通过10ms计算时间,展示了在处理40x40椭圆时的性能

python 实现统计图像上的椭圆(ellipse) 内的信息

主要的要点是:

0. 得到椭圆的长短轴方向,半径,以及圆心

import numpy as np


def get_ellipse_parameter(ellipse_info):
    """ 得到椭圆的参数 """
    long_axis_start_pt = np.array([ellipse_info[0], ellipse_info[1]])
    long_axis_end_pt = np.array([ellipse_info[2], ellipse_info[3]])
    short_axis_start_pt = np.array([ellipse_info[4], ellipse_info[5]])
    short_axis_end_pt = np.array([ellipse_info[6], ellipse_info[7]])
    long_radius = np.linalg.norm(long_axis_end_pt - long_axis_start_pt) / 2.0
    long_axis = (long_axis_end_pt - long_axis_start_pt) / long_radius / 2.0
    short_radius = np.linalg.norm(short_axis_end_pt - short_axis_start_pt) / 2.0
    short_axis = (short_axis_end_pt - short_axis_start_pt) / short_radius / 2.0
    center = (long_axis_end_pt + long_axis_start_pt) / 2.0
    return long_radius, long_axis, short_radius, short_axis, center


1. 求 ellipse 的 boundingbox , 减少计算量

def get_ellipse_bounding_box(ellipse_info):
    """ 得到 ellipse bounding box """
    assert isinstance(ellipse_info, np.ndarray), \
        r'ellipse info 输入的参数必须为 numpy 类型'
    x_array = np.array([ellipse_info[0], ellipse_info[2], ellipse_info[4], ellipse_info[6]])
    y_array = np.array([ellipse_info[1], ellipse_info[3], ellipse_info[5], ellipse_info[7]])
    min_x = min(x_array)
    max_x = max(x_array)
    min_y = min(y_array)
    max_y = max(y_array)
    return min_x, min_y, max_x, max_y

2. 判断点是否的椭圆中

def is_in_ellipse(pt, long_radius, long_axis, short_radius, short_axis, center):
    """ 判断点是否在椭圆内部 """
    normalized_pt = pt - center
    normalized_pt_x = np.dot(normalized_pt, long_axis)
    normalized_pt_y = np.dot(normalized_pt, short_axis)
    result = normalized_pt_x ** 2 / long_radius ** 2 + normalized_pt_y ** 2 / short_radius ** 2
    if result <= 1.0:
        return True
    else:
        return False

3. 调用上述方法统计计算

def cal_ellipse_statistic_info(im_2d, ellipse_info):
    """
    统计椭圆区域内的像素信息
    :param im_2d:           numpy 类型的图像信息
    :param ellipse_info:    椭圆的长段轴坐标 - 图像坐标系下
                            [long_axis_start_pt, long_axis_end_pt, short_axis_start_pt, short_axis_end_pt]
    :return statistic_info: 统计得到的像素信息 [num_of_pixels, min_value, max_value, mean_value]
    """
    assert isinstance(im_2d, np.ndarray) and isinstance(ellipse_info, np.ndarray), \
        r'输入的参数必须为 numpy 类型'

    # num_of_pixels, min_value, max_value, mean_value
    result = [None, None, None, None]
    min_x, min_y, max_x, max_y = get_ellipse_bounding_box(ellipse_info)
    if min_x < 0 or min_y < 0 or max_y >= im_2d.shape[0] or max_x >= im_2d.shape[1]:
        return result

    long_radius, long_axis, short_radius, short_axis, center = get_ellipse_parameter(ellipse_info)

    num_of_pixels = 0
    min_value = 2048
    max_value = -2048
    sum_of_pixel_values = 0
    for x in list(range(min_x, max_x)):
        for y in list(range(min_y, max_y)):
            if is_in_ellipse(np.array([x, y]), long_radius, long_axis, short_radius, short_axis, center):
                num_of_pixels += 1
                cur_value = im_2d[y, x]
                if min_value > cur_value:
                    min_value = cur_value
                if max_value < cur_value:
                    max_value = cur_value
                sum_of_pixel_values += cur_value

    if num_of_pixels > 0:
        mean_value = sum_of_pixel_values / num_of_pixels
        result = [float(num_of_pixels), float(min_value), float(max_value), float(mean_value)]
    return result

4. 测试:

if __name__ == '__main__':

    import time
    im_2d = np.ones((1024, 1024), dtype=np.int16)
    im_2d[138, 138] = 255
    im_2d[138, 130] = -200
    # ellipse_info = np.array([108, 128, 148, 128, 128, 108, 128, 148])
    ellipse_info = np.array([312, 512, 712, 512, 512, 312, 512, 712])

    begin = time.time()
    statistic_result = cal_ellipse_statistic_info(im_2d, ellipse_info)
    end = time.time()
    print('cost time {} s'.format(end - begin))

    print('num_of_pixels - min_value - max_value - mean_value : {}'.format(statistic_result))


5. 最终,时间性能

大约 40 * 40 的椭圆,计算时间大约是 10 ms


全部代码如下:

import numpy as np


def get_ellipse_parameter(ellipse_info):
    """ 得到椭圆的参数 """
    long_axis_start_pt = np.array([ellipse_info[0], ellipse_info[1]])
    long_axis_end_pt = np.array([ellipse_info[2], ellipse_info[3]])
    short_axis_start_pt = np.array([ellipse_info[4], ellipse_info[5]])
    short_axis_end_pt = np.array([ellipse_info[6], ellipse_info[7]])
    long_radius = np.linalg.norm(long_axis_end_pt - long_axis_start_pt) / 2.0
    long_axis = (long_axis_end_pt - long_axis_start_pt) / long_radius / 2.0
    short_radius = np.linalg.norm(short_axis_end_pt - short_axis_start_pt) / 2.0
    short_axis = (short_axis_end_pt - short_axis_start_pt) / short_radius / 2.0
    center = (long_axis_end_pt + long_axis_start_pt) / 2.0
    return long_radius, long_axis, short_radius, short_axis, center


def is_in_ellipse(pt, long_radius, long_axis, short_radius, short_axis, center):
    """ 判断点是否在椭圆内部 """
    normalized_pt = pt - center
    normalized_pt_x = np.dot(normalized_pt, long_axis)
    normalized_pt_y = np.dot(normalized_pt, short_axis)
    result = normalized_pt_x ** 2 / long_radius ** 2 + normalized_pt_y ** 2 / short_radius ** 2
    if result <= 1.0:
        return True
    else:
        return False


def get_ellipse_bounding_box(ellipse_info):
    """ 得到 ellipse bounding box """
    assert isinstance(ellipse_info, np.ndarray), \
        r'ellipse info 输入的参数必须为 numpy 类型'
    x_array = np.array([ellipse_info[0], ellipse_info[2], ellipse_info[4], ellipse_info[6]])
    y_array = np.array([ellipse_info[1], ellipse_info[3], ellipse_info[5], ellipse_info[7]])
    min_x = min(x_array)
    max_x = max(x_array)
    min_y = min(y_array)
    max_y = max(y_array)
    return min_x, min_y, max_x, max_y


def cal_ellipse_statistic_info(im_2d, ellipse_info):
    """
    统计椭圆区域内的像素信息
    :param im_2d:           numpy 类型的图像信息
    :param ellipse_info:    椭圆的长段轴坐标 - 图像坐标系下
                            [long_axis_start_pt, long_axis_end_pt, short_axis_start_pt, short_axis_end_pt]
    :return statistic_info: 统计得到的像素信息 [num_of_pixels, min_value, max_value, mean_value]
    """
    assert isinstance(im_2d, np.ndarray) and isinstance(ellipse_info, np.ndarray), \
        r'输入的参数必须为 numpy 类型'

    # num_of_pixels, min_value, max_value, mean_value
    result = [None, None, None, None]
    min_x, min_y, max_x, max_y = get_ellipse_bounding_box(ellipse_info)
    if min_x < 0 or min_y < 0 or max_y >= im_2d.shape[0] or max_x >= im_2d.shape[1]:
        return result

    long_radius, long_axis, short_radius, short_axis, center = get_ellipse_parameter(ellipse_info)

    num_of_pixels = 0
    min_value = 2048
    max_value = -2048
    sum_of_pixel_values = 0
    for x in list(range(min_x, max_x)):
        for y in list(range(min_y, max_y)):
            if is_in_ellipse(np.array([x, y]), long_radius, long_axis, short_radius, short_axis, center):
                num_of_pixels += 1
                cur_value = im_2d[y, x]
                if min_value > cur_value:
                    min_value = cur_value
                if max_value < cur_value:
                    max_value = cur_value
                sum_of_pixel_values += cur_value

    if num_of_pixels > 0:
        mean_value = sum_of_pixel_values / num_of_pixels
        result = [float(num_of_pixels), float(min_value), float(max_value), float(mean_value)]
    return result


if __name__ == '__main__':

    import time
    im_2d = np.ones((1024, 1024), dtype=np.int16)
    im_2d[138, 138] = 255
    im_2d[138, 130] = -200
    # ellipse_info = np.array([108, 128, 148, 128, 128, 108, 128, 148])
    ellipse_info = np.array([312, 512, 712, 512, 512, 312, 512, 712])

    begin = time.time()
    statistic_result = cal_ellipse_statistic_info(im_2d, ellipse_info)
    end = time.time()
    print('cost time {} s'.format(end - begin))

    print('num_of_pixels - min_value - max_value - mean_value : {}'.format(statistic_result))


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值