目前我正在使用下面的代码拍摄图像,其中每列像素代表现实世界中的不同宽度(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]))
我真的很感激任何帮助:)
@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)