什么导致椭圆的外接矩形绘制不正确?

-2 投票
0 回答
38 浏览
提问于 2025-04-12 06:15

我在画椭圆的外部矩形时遇到了问题。

未考虑弧度

有一个椭圆的外部矩形画得很好,但另一个却不对。我不知道是什么导致了这种情况。 我用文本注释文件,里面有圆心、长半轴、短半轴和旋转角度,像这样。

我还考虑了弧度和角度的问题,加入弧度考虑,但似乎还是不行。

2
507.8829    75.5720     62.6301     44.5533     -32.4339
509.4677    113.7811    99.0642     58.6944     -76.6004

我用的这段代码

def get_ellipse_param(major_radius, minor_radius, angle):
    a, b = major_radius, minor_radius
    sin_theta = np.sin(-angle)
    cos_theta = np.cos(-angle)
    A = a**2 * sin_theta**2 + b**2 * cos_theta**2
    B = 2 * (a**2 - b**2) * sin_theta * cos_theta
    C = a**2 * cos_theta**2 + b**2 * sin_theta**2
    F = -a**2 * b**2
    return A, B, C, F

def calculate_rectangle(A, B, C, F):
    y = np.sqrt(4*A*F / (B**2 - 4*A*C))
    y1, y2 = -np.abs(y), np.abs(y)
    x = np.sqrt(4*C*F / (B**2 - 4*C*A))
    x1, x2 = -np.abs(x), np.abs(x)
    
    return (x1, y1), (x2, y2)

def get_rectangle(center_x, center_y,major_radius, minor_radius, angle):
    # new add
    angle = angle * math.pi / 180

    A, B, C, F = get_ellipse_param(major_radius, minor_radius, -angle)
    p1, p2 = calculate_rectangle(A, B, C, F)
    print(p1, p2)

    xmin = min(center_x + p1[0],center_x + p2[0])
    xmax = max(center_x + p1[0],center_x + p2[0])
    ymin = min(center_y + p1[1],center_y + p2[1])
    ymax = max(center_y + p1[1],center_y + p2[1])

    print(xmin, ymin, xmax, ymax)
    return xmin, ymin, xmax, ymax

xml2txt.py


import os
import math
import xml.etree.ElementTree as ET
from PIL import Image
import numpy as np

# 从指定目录下读取所有的txt问价
def get_all_txt_file(path):
    txt_files_path = []
    for root, dirs, files in os.walk(path):
        for file in files:
            if file.endswith('.txt'):
                txt_files_path.append(os.path.join(root, file))
    return txt_files_path


def get_ellipse_param(major_radius, minor_radius, angle):
    a, b = major_radius, minor_radius
    sin_theta = np.sin(-angle)
    cos_theta = np.cos(-angle)
    A = a**2 * sin_theta**2 + b**2 * cos_theta**2
    B = 2 * (a**2 - b**2) * sin_theta * cos_theta
    C = a**2 * cos_theta**2 + b**2 * sin_theta**2
    F = -a**2 * b**2
    return A, B, C, F

def calculate_rectangle(A, B, C, F):
    '''
    椭圆上下外接点的纵坐标值
    '''
    y = np.sqrt(4*A*F / (B**2 - 4*A*C))
    y1, y2 = -np.abs(y), np.abs(y)
    
    '''
    椭圆左右外接点的横坐标值
    '''
    x = np.sqrt(4*C*F / (B**2 - 4*C*A))
    x1, x2 = -np.abs(x), np.abs(x)
    
    return (x1, y1), (x2, y2)

def get_rectangle(center_x, center_y,major_radius, minor_radius, angle):
    A, B, C, F = get_ellipse_param(major_radius, minor_radius, -angle)
    p1, p2 = calculate_rectangle(A, B, C, F)
    print(p1, p2)

    xmin = min(center_x + p1[0],center_x + p2[0])
    xmax = max(center_x + p1[0],center_x + p2[0])
    ymin = min(center_y + p1[1],center_y + p2[1])
    ymax = max(center_y + p1[1],center_y + p2[1])

    print(xmin, ymin, xmax, ymax)
    return xmin, ymin, xmax, ymax




def generate_xml(xml_file_name,annotation_data):
    annotation = ET.Element("annotation")

    folder = ET.SubElement(annotation, "folder")
    folder.text = annotation_data["folder"]

    filename = ET.SubElement(annotation, "filename")
    filename.text = annotation_data["filename"]

    path = ET.SubElement(annotation, "path")
    path.text = annotation_data["path"]

    source = ET.SubElement(annotation, "source")
    database = ET.SubElement(source, "database")
    database.text = annotation_data["database"]

    size = ET.SubElement(annotation, "size")
    width = ET.SubElement(size, "width")
    width.text = str(annotation_data["width"])
    height = ET.SubElement(size, "height")
    height.text = str(annotation_data["height"])
    depth = ET.SubElement(size, "depth")
    depth.text = str(annotation_data["depth"])

    segmented = ET.SubElement(annotation, "segmented")
    segmented.text = str(annotation_data["segmented"])

    for obj_data in annotation_data["objects"]:
        object_element = ET.SubElement(annotation, "object")
        name = ET.SubElement(object_element, "name")
        name.text = obj_data["name"]
        pose = ET.SubElement(object_element, "pose")
        pose.text = obj_data["pose"]
        truncated = ET.SubElement(object_element, "truncated")
        truncated.text = str(obj_data["truncated"])
        difficult = ET.SubElement(object_element, "difficult")
        difficult.text = str(obj_data["difficult"])

        bndbox = ET.SubElement(object_element, "bndbox")
        xmin = ET.SubElement(bndbox, "xmin")
        xmin.text = str(obj_data["xmin"])
        ymin = ET.SubElement(bndbox, "ymin")
        ymin.text = str(obj_data["ymin"])
        xmax = ET.SubElement(bndbox, "xmax")
        xmax.text = str(obj_data["xmax"])
        ymax = ET.SubElement(bndbox, "ymax")
        ymax.text = str(obj_data["ymax"])

    xml_tree = ET.ElementTree(annotation)
    xml_tree.write(xml_file_name, encoding="utf-8", xml_declaration=True)

if __name__ == '__main__':
    input_path = "gt"
    input_img_path = "images"
    output_path = "true"
    txt_files_path = get_all_txt_file(input_path)
    # print(txt_files_path)
    for file in txt_files_path:
        print(file + ' is processing...')
        txt_content = list(open(file, 'r').readlines())
        ellipse_count = int(txt_content[0])
        print(ellipse_count,file)
        img_path =  input_img_path + "/" +file.split("\\")[-1].replace(".txt", "").replace("gt_","")
        img = Image.open(img_path)
        data ={}
        data["folder"] = "JPEGImages"
        data["filename"] = file.split("\\")[-1].split(".")[0]+".jpg"
        data["path"] = img_path
        data["database"] = "Unknown"
        data["width"] = img.width
        data["height"] = img.height
        data["depth"] = len(img.getbands())
        data["segmented"] = 0
        data["objects"] = []
        for i in range(1, ellipse_count + 1):
            ellipse = txt_content[i].split()
            x = float(ellipse[0])
            y = float(ellipse[1])
            a = float(ellipse[2])
            b = float(ellipse[3])
            angle = float(ellipse[4])
            # tangents = get_tangents(y, x, a, b,angle)
            if a<b:
                temp = a 
                a = b
                b = temp
            # tangents = get_rectangle(x,y,a,b,angle)
            tangents = get_rectangle(y,x,a,b,angle)

            obj_data = {
                "name": "ellipse",
                "pose": "Unspecified",
                "truncated": 0,
                "difficult": 0,
                "xmin": tangents[0],
                "ymin": tangents[1],
                "xmax": tangents[2],
                "ymax": tangents[3]
            }
            data["objects"].append(obj_data)
            print(tangents)
        data["output_file"] = "annotation.xml"
        img_path = output_path + "/" + file.split("\\")[-1].replace(".png.txt", ".xml").replace(".jpg.txt", ".xml")
        img_path = img_path.replace("gt_", "")
        generate_xml(img_path,data)
       
  

display.py

import os
import xml.etree.ElementTree
import cv2 as cv

xmlPath = "true/"
xmlFiles = [name for name in os.listdir(xmlPath) if name.endswith('.xml')]

for i in range(len(xmlFiles)):
    file = xml.etree.ElementTree.parse(xmlPath + xmlFiles[i])
    cnt = len(file.findall('object'))
    print(cnt)
    # imgPath = xmlFiles[i].replace("xml", "jpg")  # prasad
    imgPath = xmlFiles[i].replace("xml", "png")
    img = cv.imread("images/" + imgPath)
    for obj in file.findall('object'):
        xMin = float(obj.find('bndbox').find('xmin').text)
        yMin = float(obj.find('bndbox').find('ymin').text)
        xMax = float(obj.find('bndbox').find('xmax').text)
        yMax = float(obj.find('bndbox').find('ymax').text)
        print(xMin, yMax, xMax, yMin)

        # 通过四个参数画正方形
        print(xmlFiles[i])

        xMax = int(xMax)
        yMin = int(yMin)
        xMin = int(xMin)
        yMax = int(yMax)

        # 矩形左上角和右上角的坐标,绘制一个绿色矩形
        ptLeftTop = (xMin, yMax)
        ptRightBottom = (xMax, yMin)

        point_color = (0, 255, 0)
        thickness = 1
        lineType = 4
        cv.rectangle(img, ptLeftTop, ptRightBottom, point_color, thickness, lineType)
        
    cv.imwrite("re/" + imgPath, img)
    cv.imshow("img",img)
    cv.waitKey(0)
    
    break
    

0 个回答

暂无回答

撰写回答