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

xvw2m8pv  于 2023-05-18  发布在  其他
关注(0)|答案(1)|浏览(163)

目前,我正在使用下面的代码来拍摄一张图像,其中每列像素代表真实的世界中不同的宽度(mm)。想象一下,一个标签缠绕在一个瓶子上。我的输入图像是当你直视瓶子时看到的(较少透视)。我试图解开标签,使展平的结果有一个精确的1 pixel:1 mm的比例。瓶子也不是圆形的,但我有一个方程式来表示它的曲率。有没有更好的方法来做到这一点,结果总是相同的,并且解拉伸的图像更均匀?
见下面的顶部图像是原始图像,底部是我希望实现的。

下面的等式和曲线给出了每列像素的压缩因子,其中列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]))

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

nfeuvbwi

nfeuvbwi1#

@Christoph Rackwitz你是传奇人物。多谢提醒。下面的代码运行得很好:)。下面的图片是生产线上的辊子。这些辊中的每一个具有相同的宽度。使用这个方法,我可以生成pol1d来确定正确的Map,这样所有的滚轮现在看起来都是相同的宽度,使用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)

相关问题