What causes the ellipse's circumscribed rectangle to draw incorrectly?

40 Views Asked by At

I'm having trouble drawing the external rectangle of an ellipse.

未考虑弧度

one ellipse is successfulily use rectangle covered, but the other is false. I not know what lead to this situation. I use txt to annotate the file, which has the center of the circle, the major semi-axis, the minor semi-axis, and the rotation angle.like this

Added the issue of radians and angles 加入弧度考虑 but it just like not work

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

and i use this code

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

There are 0 best solutions below