You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于网格的地毯图像变换出现镜像反转问题排查求助

图像校正网格变换镜像反转问题排查

我拍摄了一张倾斜放置在地面的地毯图像,随后为地毯所有点创建了等距网格,网格点按顺时针顺序存储(左上、右上、右下、左下)。尝试使用以下Python+OpenCV代码逐网格将该图像变换为正置地毯,但输出图像出现了镜像反转的情况,我标记在原图上的红色角标1、2、3、4位置错乱。

import cv2
import numpy as np
from final.mesh import create_mesh_points
import csv

def generate_destination_mesh(target_size, num_divisions):
    target_width, target_height = target_size

    # Using integer division for cells; the last division might be slightly larger to cover the whole image
    cell_width = target_width // (num_divisions - 1)
    cell_height = target_height // (num_divisions - 1)

    extra_width = target_width % (num_divisions - 1)
    extra_height = target_height % (num_divisions - 1)

    dst_points = np.zeros((num_divisions, num_divisions, 2), dtype=np.float32)
    
    for i in range(num_divisions):
        for j in range(num_divisions):
            x = j * cell_width if j < num_divisions - 1 else j * cell_width + extra_width
            y = i * cell_height if i < num_divisions - 1 else i * cell_height + extra_height
            dst_points[i, j] = [x, y]
            
    
    return dst_points


def transform_rug(image, mesh_points, num_divisions, target_size, dst_mesh_points, csv_filename):
    target_width, target_height = target_size
    transformed_rug = np.zeros((target_height, target_width, 3), dtype=np.uint8)

    with open(csv_filename, 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(['Cell Index i', 'Cell Index j', 'Source Points', 'Destination Points'])

        for i in range(49):
            for j in range(49):
                src_points = np.array([
                    mesh_points[i][j],       # Top-left
                    mesh_points[i][j+1],   # Top-right
                    mesh_points[i + 1][j + 1],  # Bottom-right
                    mesh_points[i+1][j]    # Bottom-left
                ], dtype=np.float32)

                dst_points = np.array([
                    dst_mesh_points[i][j],       # Top-left
                    dst_mesh_points[i][j + 1],   # Top-right
                    dst_mesh_points[i + 1][j + 1],  # Bottom-right
                    dst_mesh_points[i + 1][j]    # Bottom-left
                ], dtype=np.float32)

                
                matrix, _ = cv2.findHomography(src_points, dst_points)
                warped_cell = cv2.warpPerspective(image, matrix, (target_width, target_height))

                # Place the warped cell into the correct position of the transformed rug ## Harcoding below to troubleshoot
                start_y = i * target_height // num_divisions
                end_y = (i + 1) * target_height // num_divisions
                start_x = j * target_width // num_divisions
                end_x = (j + 1) * target_width // num_divisions
                transformed_rug[start_y:end_y, start_x:end_x] = warped_cell[start_y:end_y, start_x:end_x]

                writer.writerow([i, j, src_points.tolist(), dst_points.tolist(), start_x,start_y,end_x,end_y])


    return transformed_rug



# Load your original rug image
source_image_path = 'images/marked.png'
original_rug = cv2.imread(source_image_path)

# Set the number of divisions in your grid
num_divisions = 50  # Change this based on your actual divisions

mesh_points = create_mesh_points(source_image_path,num_divisions)
csv_filename = 'grid_points.csv'

# Set your target size (width, height)
target_size = (1800, 2700)  # Adjust as per your actual needs

# Generate the destination mesh
destination_mesh_points = generate_destination_mesh(target_size, num_divisions)


# Transform the rug
final_rug = transform_rug(original_rug, mesh_points, num_divisions, target_size,destination_mesh_points, csv_filename)

# Save or display the final transformed rug
#cv2.imshow('Transformed Rug', final_rug)
cv2.imwrite('transformed.png', final_rug)
#cv2.waitKey(0)
#cv2.destroyAllWindows()

以下是源网格、目标网格及单元格放置坐标的前5组数据:

Cell Index iCell Index jSource PointsDestination PointsStart XStart YEnd XEnd Y
00[[1675.0, 99.0], [1705.0, 91.0], [1686.0, 155.0], [1656.0, 161.0]][[0.0, 0.0], [36.0, 0.0], [36.0, 55.0], [0.0, 55.0]]003654
01[[1656.0, 161.0], [1686.0, 155.0], [1666.0, 215.0], [1637.0, 222.0]][[36.0, 0.0], [72.0, 0.0], [72.0, 55.0], [36.0, 55.0]]3607254
02[[1637.0, 222.0], [1666.0, 215.0], [1645.0, 276.0], [1617.0, 284.0]][[72.0, 0.0], [108.0, 0.0], [108.0, 55.0], [72.0, 55.0]]72010854
03[[1617.0, 284.0], [1645.0, 276.0], [1623.0, 335.0], [1595.0, 344.0]][[108.0, 0.0], [144.0, 0.0], [144.0, 55.0], [108.0, 55.0]]108014454
04[[1595.0, 344.0], [1623.0, 335.0], [1601.0, 395.0], [1572.0, 405.0]][[144.0, 0.0], [180.0, 0.0], [180.0, 55.0], [144.0, 55.0]]144018054

输出图像:
Transformed rug image

原始输入图像:
Original input image

我已逐行检查CSV中的网格点,未发现明显问题,但始终找不到导致镜像反转的原因。现附上用于创建网格的代码:

import cv2
import numpy as np
from sourceSidePoints import process_image_and_get_side_points

def create_mesh_points(source_image_path, num_divisions, dilation=40):
    # Load image and side points
    side_points, img_with_corners = process_image_and_get_side_points(source_image_path,num_divisions)

    # Reverse points where necessary
    side_points[2] = side_points[2][::-1]  # Reverse bottom side points
    side_points[3] = side_points[3][::-1]  # Reverse left side points

    def adjust_boundaries(side_points, dilation):
        # Adjusting top side (Subtract from y)
        top = np.array([[x, y - dilation] for x, y in side_points[0]])

        # Adjusting bottom side (Add to y)
        bottom = np.array([[x, y + dilation] for x, y in side_points[2]])

        # Adjusting right side (Add to x)
        right = np.array([[x + dilation, y] for x, y in side_points[1]])

        # Adjusting left side (Subtract from x)
        left = np.array([[x - dilation, y] for x, y in side_points[3]])

        return [top, right, bottom, left]

    # Apply the dilation to the side points
    adjusted_side_points = adjust_boundaries(side_points, dilation)

    # Assigning points to variables for clarity
    top = adjusted_side_points[0]
    right = adjusted_side_points[1]
    bottom = adjusted_side_points[2]
    left = adjusted_side_points[3]

    # Assuming mesh_points is a 2D array of coordinates [num_divisions][num_divisions]
    mesh_points = np.zeros((num_divisions, num_divisions, 2), dtype=int)

    # Create the mesh by directly using the points provided
    for i in range(num_divisions):
        for j in range(num_divisions):
            # Assign boundary points directly to ensure they remain on the edges
            if i == 0:
                mesh_points[i][j] = left[j]  # First column from left

            elif i == num_divisions - 1:
                mesh_points[i][j] = right[j]  # Last column from right

            elif j == 0:
                mesh_points[i][j] = top[i]  # First row from top

            elif j == num_divisions - 1:
                mesh_points[i][j] = bottom[i]  # Last row from bottom

            else:
                # Calculate interior mesh points
                horizontal_point = (left[j] * (num_divisions - i) / num_divisions) + (right[j] * i / num_divisions)
                vertical_point = (top[i] * (num_divisions - j) / num_divisions) + (bottom[i] * j / num_divisions)
                mesh_point = (horizontal_point + vertical_point) / 2
                mesh_points[i][j] = mesh_point

    return mesh_points

if __name__ == "__main__":
    source_image_path = '../images/marked.png'
       # Drawing lines and circles
    img_with_corners = cv2.imread(source_image_path)
    num_divisions = 50
    mesh_points = create_mesh_points(source_image_path, num_divisions)
    

 
    # Drawing the horizontal lines for every row
    for i in range(num_divisions):
        for j in range(num_divisions - 1):
            start_point = tuple(np.round(mesh_points[i][j]).astype(int))
            end_point = tuple(np.round(mesh_points[i][j + 1]).astype(int))
            cv2.line(img_with_corners, start_point, end_point, (255, 0, 0, 255), 3)

    # Drawing the vertical lines for every column
    for j in range(num_divisions):
        for i in range(num_divisions - 1):
            start_point = tuple(np.round(mesh_points[i][j]).astype(int))
            end_point = tuple(np.round(mesh_points[i + 1][j]).astype(int))
            cv2.line(img_with_corners, start_point, end_point, (255, 0, 0, 255), 3)

    cv2.imshow('Mesh Overlay', img_with_corners)
    cv2.imwrite('mesh2.png', img_with_corners)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

目前我已通过ImageMagick的Shepards畸变实现了图像校正效果,但希望能修复当前的网格变换方案,以获得更灵活的控制,恳请帮忙排查代码中的问题。

内容的提问来源于stack exchange,提问作者Karan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:47:03