如何使用 opencv 对图像应用非均匀拉伸

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

目前我正在使用下面的代码拍摄图像,其中每列像素代表现实世界中的不同宽度(mm)。想象一个标签缠绕在瓶子上。我的输入图像是您直视瓶子时所看到的(较少视角)。我正在尝试打开该标签,以便展平结果具有精确的 1 像素:1 毫米比率。瓶子也不是圆形的,但我有一个方程式来表示它的曲率。 有没有更好的方法来做到这一点,结果始终相同并且去拉伸图像更均匀?

见下图,上图是原始图像,下图是我希望达到的效果。

下面的等式和曲线为我提供了每列像素的压缩因子,其中第 1741 列的像素代表 0.773802mm

目前我正在使用下面的概率代码根据压缩因子复制/删除像素列。由于概率性质,给定相同的输入,每个输出都是不同的,拉伸校正并不像我想要的那样均匀。 注意:上面的条纹图像不是用这段代码生成的

import random
import cv2
import numpy as np


def regularise_image_stretch(img: cv2.Mat, compensations: np.ndarray) -> cv2.Mat:
    '''apply a non uniform stretch to an image based on an equation that maps column idx
    to compression/stretch needed to make the pixel:mm ratio uniform across all cols

    Args:
        img (cv2.Mat): non uniform image
        compensations (np.ndarray): array of compensations per column idx generated from an equation

    Returns:
        cv2.Mat: an image where every pixel represents 1mm
    '''
    def decision(val: float) -> tuple[str, bool, float]:
        '''Based on the compression factor use a probabistic approach to decide 
        whether to insert a copy of the previous column or to delete a column. 

        Args:
            val (float): compression value

        Returns:
            tuple[str, bool, float]: ("add" || "remove", should be applied, probability)
        '''
        addrem = "rem"
        probability = 1 - val
        if probability > 0:
            addrem = "add"

        probability = abs(probability)

        return (addrem, random.random() < probability, probability)

    modimg = img.copy()

    res = list(map(decision, compensations))
    new_img = []
    previous_col = modimg[:, 0, :]

    # add/replicate columns based on compression factor
    for i, col in enumerate(modimg.transpose(1,0,2)):
        addrem, shouldapply, _ = res[i]
        new_img.append(col)

        if shouldapply:
            if addrem == "add":
                new_img.append(previous_col)
            else:
                new_img.pop(-1)

        previous_col = col

    # as a list is being used above fix image orientation
    new_img = cv2.rotate(np.array(new_img), cv2.ROTATE_90_COUNTERCLOCKWISE)
    new_img = cv2.flip(np.array(new_img), 0)
    new_img = cv2.resize(new_img, (img.shape[1], img.shape[0]))
    return new_img


img = cv2.imread("./stripes.jpg")

new_img = regularise_image_stretch(img, compensations)
cv2.imwrite("./modifiend2.png", np.vstack([new_img, img]))

我真的很感激任何帮助:)

python opencv image-processing geometry linear-algebra
1个回答
0
投票

@Christoph Rackwitz 你这个传奇人物。谢谢你的提示。下面的代码运行完美:)。下图是生产线上的滚筒。这些滚筒中的每一个都具有相同的宽度。使用这个我能够生成 pol1d 来确定正确的映射,这样所有的滚轮现在使用 cv.map 看起来都是相同的宽度。

import cv2
import numpy as np
from matplotlib import pyplot as plt


def update_map(map_x, map_y, poly_vals):
    for i in range(map_x.shape[0]):
        map_x[i,:] = [poly_vals[x] for x in range(map_x.shape[1])]
    for j in range(map_y.shape[1]):
        map_y[:,j] = [y for y in range(map_y.shape[0])]

            
src = cv2.imread('./dec1.jpg', cv2.IMREAD_COLOR)

    
map_x = np.zeros((src.shape[0], src.shape[1]), dtype=np.float32)
map_y = np.zeros((src.shape[0], src.shape[1]), dtype=np.float32)


""" poly = poly1d([-1.88998073e-30,  4.54152495e-26, -4.63866537e-22,  2.57875197e-18,
       -7.81961948e-15,  8.97968101e-12, -4.74328547e-09,  1.00701327e-04,
        7.72461327e-01, -2.75718623e-01])"""
poly_vals = np.poly1d(mypoly)(range(src.shape[1]))
                           

update_map(map_x, map_y, poly_vals)
dst = cv2.remap(src, map_x, map_y, cv2.INTER_LINEAR)
cv2.imwrite("destretched.png", np.vstack([dst, src]))
plt.imshow(dst)
© www.soinside.com 2019 - 2024. All rights reserved.