如何优化这个Python代码,以最少的行数提供最详细的信息

问题描述 投票:0回答:1

我有这个Python代码,它获取图像,并将其转换成可以由Hackclub的Blot绘制的东西。 Blot 有一个非常简单的坐标来坐标绘制线系统。目前这段代码生成了 80000 行,我想在不丢失太多细节的情况下减少它。任何建议。

[https://github.com/GeoWizard4645/BlotInator/blob/main/README.md](https://github.com/GeoWizard4645/BlotInator/blob/main/README.md)
`

from PIL import Image, ImageOps
import numpy as np
import cv2
import matplotlib.pyplot as plt
from skimage import measure, transform
import math


# Set the detail level (1 for maximum detail, 0 for minimal detail)
detail_level = 0.8  # Higher detail level for better quality

# Function to process the image and extract edges with higher precision
def process_image(image_path):
    # Load image and convert to grayscale
    image = Image.open(image_path).convert("L")
    image = ImageOps.mirror(image)  # Mirror the image horizontally
    image = ImageOps.invert(image)  # Invert to make the background black and foreground white
    image = image.rotate(180)  # Rotate the image by 180 degrees
    image_array = np.array(image)

    # Calculate ksize (ensuring it's odd and positive)
    ksize_value = max(3, int(round(-3.333333333333 * detail_level + 5.666666666666666667)))
    if ksize_value % 2 == 0:
        ksize_value += 1
    ksize = (ksize_value, ksize_value)

    # Apply a slight blur to reduce noise
    blurred = cv2.GaussianBlur(image_array, ksize, 0)

    # Use Canny edge detection with lower thresholds for more sensitivity
    canny_threshold1 = int(round(-33.333333333 * detail_level + 56.6666666666667))
    canny_threshold2 = int(round(-83.33333333 * detail_level + 166.666666667))
    edges = cv2.Canny(blurred, canny_threshold1, canny_threshold2)

    # Optionally, thicken the edges slightly
    edges = transform.rescale(edges, 1.0, anti_aliasing=True)
    edges = cv2.dilate(edges, np.ones((2,2),np.uint8), iterations=1)

    # Use contours to find connected components
    contours = measure.find_contours(edges, 0.8)
    
    return contours, image_array.shape

# Function to generate the Blot code
def generate_blot_code(contours, dimensions, detail_level=0.8):
    maxDimension_y = 0
    maxDimension_x = 0    
    print("Generating Blot code...")
    lines = []
    
    # Set a fixed tolerance for fine control over details
    if -15 * detail_level + 13>0:
        max_tolerance =  -15 * detail_level + 13>0 # High tolerance for significant simplification
    else :
        max_tolerance = 0.1
    if -15 * detail_level + 13>0:
        min_tolerance =  -1.5 * detail_level + 1.3>0 # High tolerance for significant simplification
    else :
        min_tolerance = 0.01
    tolerance = (1 - detail_level) * (max_tolerance - min_tolerance) + min_tolerance
    
    # Calculate bounding box of all contours
    all_points = np.concatenate(contours)
    min_y, min_x = np.min(all_points, axis=0)
    max_y, max_x = np.max(all_points, axis=0)
    
    # Calculate scale and translation to center the drawing
    scale_x = (dimensions[1] - 1) / (max_x - min_x)
    scale_y = (dimensions[0] - 1) / (max_y - min_y)
    scale = min(scale_x, scale_y)  # Maintain aspect ratio by using the smallest scale factor
    
    translate_x = (dimensions[1] - (max_x - min_x) * scale) / 2 - min_x * scale
    translate_y = (dimensions[0] - (max_y - min_y) * scale) / 2 - min_y * scale
    
    for contour in contours:
        # Smooth the contour and simplify based on the detail level
        smoothed_contour = measure.approximate_polygon(contour, tolerance=tolerance)
        if len(smoothed_contour) >= 2:  # Only consider meaningful contours
            for i in range(len(smoothed_contour) - 1):
                y1, x1 = smoothed_contour[i]
                y2, x2 = smoothed_contour[i + 1]
                
                # Scale and translate coordinates
                x1 = int(x1 * scale + translate_x)
                y1 = int(y1 * scale + translate_y)
                x2 = int(x2 * scale + translate_x)
                y2 = int(y2 * scale + translate_y)
                
                lines.append(f"finalLines.push([[{x1}, {y1}], [{x2}, {y2}]]);\n")
                if x1 > maxDimension_x:
                    maxDimension_x = x1 +5
                if x2 > maxDimension_x:
                    maxDimension_x = x2 +5
                if y1 > maxDimension_x:
                    maxDimension_x = y1 +5
                if y2 > maxDimension_x:
                    maxDimension_x = y2 +5           

    blot_code = [
        "// Produced by Vivaan Shahani, based on Aditya Anand's Blotinator, not human-written\n",
        f"setDocDimensions({str(maxDimension_x)}, {str(maxDimension_y)});\n",
        "const finalLines = [];\n"
    ]
    blot_code.extend(lines)
    blot_code.append("drawLines(finalLines);")

    return blot_code

# Main function
if __name__ == "__main__":
    # Use the correct image path
    image_path = '/Users/vivaanshahani/Downloads/IMG_9654.png'

    # Process the image
    contours, dimensions = process_image(image_path)

    # Generate the Blot code with the specified detail level
    blot_code = generate_blot_code(contours, dimensions, detail_level)

    # Write the Blot code to a file
    output_path = "/Users/vivaanshahani/Downloads/Blotcode.js"
    with open(output_path, "w") as file:
        file.writelines(blot_code)

    print(f"Blot code generated and saved to {output_path}")

我尝试过尝试,唯一有效的似乎是调整细节值并丢失细节。

python drawing
1个回答
0
投票

调整轮廓近似中的公差:

measure.approximate_polygon 函数根据容差值减少轮廓中的点数。 您可以过滤掉对整体形状影响不大的较小、不太重要的轮廓,而不是处理所有轮廓。这种方法通过仅关注最重要的轮廓来减少线条数量。

具有更高精度的图像处理和边缘提取功能

def process_image(image_path, downscale_factor=0.5):
    # Load image and convert to grayscale
    image = Image.open(image_path).convert("L")
    image = ImageOps.mirror(image)  # Mirror the image horizontally
    image = ImageOps.invert(image)  # Invert to make the background black and foreground white
    image = image.rotate(180)  # Rotate the image by 180 degrees
    
    # Downscale the image
    image = image.resize((int(image.width * downscale_factor), int(image.height * downscale_factor)))
    image_array = np.array(image)

    # Calculate ksize (ensuring it's odd and positive)
    ksize_value = max(3, int(round(-3.333333333333 * detail_level + 5.666666666666666667)))
    if ksize_value % 2 == 0:
        ksize_value += 1
    ksize = (ksize_value, ksize_value)

    # Apply a slight blur to reduce noise
    blurred = cv2.GaussianBlur(image_array, ksize, 0)

    # Use Canny edge detection with higher thresholds to reduce edges
    canny_threshold1 = int(round(-20.333333333 * detail_level + 66.6666666666667))
    canny_threshold2 = int(round(-50.33333333 * detail_level + 150.666666667))
    edges = cv2.Canny(blurred, canny_threshold1, canny_threshold2)

    # Optionally, thicken the edges slightly
    edges = transform.rescale(edges, 1.0, anti_aliasing=True)
    edges = cv2.dilate(edges, np.ones((2,2),np.uint8), iterations=1)

    # Use contours to find connected components
    contours = measure.find_contours(edges, 0.8)
    
    return contours, image_array.shape

# Main function remains the same
© www.soinside.com 2019 - 2024. All rights reserved.