opencv warp仿射期间图像强度分布变化
Image intensity distribution changes during opencv warp affine
我在 windows 7
上使用 python 3.8.5 和 opencv 4.5.1
我正在使用以下代码来旋转图像。
def pad_rotate(image, ang, pad, pad_value=0):
(h, w) = image.shape[:2]
#create larger image and paste original image at the center.
# this is done to avoid any cropping during rotation
nH, nW = h + 2*pad, w + 2*pad #new height and width
cY, cX = nW//2, nH//2 #center of the new image
#create new image with pad_values
newImg = np.zeros((h+2*pad, w+2*pad), dtype=image.dtype)
newImg[:,:] = pad_value
#paste new image at the center
newImg[pad:pad+h, pad:pad+w] = image
#rotate CCW (for positive angles)
M = cv2.getRotationMatrix2D(center=(cX, cY), angle=ang, scale=1.0)
rotImg = cv2.warpAffine(newImg, M, (nW, nH), cv2.INTER_CUBIC,
borderMode=cv2.BORDER_CONSTANT, borderValue=pad_value)
return rotImg
我的问题是旋转后,图像强度分布与原始图像不同。
编辑问题的以下部分以澄清问题
img = np.random.rand(500,500)
Rimg = pad_rotate(img, 15, 300, np.nan)
以下是这些图片的样子:
他们的强度明显改变了:
np.percentile(img, [20, 50, 80])
# prints array([0.20061218, 0.50015415, 0.79989986])
np.nanpercentile(Rimg, [20, 50, 80])
# prints array([0.32420028, 0.50031483, 0.67656537])
有人可以告诉我如何避免这种规范化吗?
插值的平均效果改变了分布...
注:
您的代码示例中存在错误(与百分位数无关)。
warpAffine
的第 4 个参数是 dst
.
将 cv2.warpAffine(newImg, M, (nW, nH), cv2.INTER_CUBIC
替换为:
cv2.warpAffine(newImg, M, (nW, nH), flags=cv2.INTER_CUBIC
我尝试简化重现问题的代码示例。
代码示例使用线性插值、1 度旋转且没有 NaN 值。
import numpy as np
import cv2
img = np.random.rand(1000, 1000)
M = cv2.getRotationMatrix2D((img.shape[1]//2, img.shape[0]//2), 1, 1) # Rotate by 1 degree
Rimg = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), flags=cv2.INTER_LINEAR) # Use Linear interpolation
Rimg = Rimg[20:-20, 20:-20] # Crop the part without the margins.
print(np.percentile(img, [20, 50, 80])) #[0.20005696 0.49990526 0.79954818]
print(np.percentile(Rimg, [20, 50, 80])) #[0.32244747 0.4998595 0.67698961]
cv2.imshow('img', img)
cv2.imshow('Rimg', Rimg)
cv2.waitKey()
cv2.destroyAllWindows()
当我们禁用插值时,
Rimg = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), flags=cv2.INTER_NEAREST)
百分位数是:[0.19943713 0.50004768 0.7995525 ].
显示平均元素改变分布的更简单示例:
A = np.random.rand(10000000)
B = (A[0:-1:2] + A[1::2])/2 # Averaging every two elements.
print(np.percentile(A, [20, 50, 80])) # [0.19995436 0.49999472 0.80007232]
print(np.percentile(B, [20, 50, 80])) # [0.31617922 0.50000145 0.68377251]
为什么插值会使分布偏向中位数?
我不是数学家。
我相信你能得到更好的解释...
这是一个直观的例子:
假设在 [0, 1].
范围内存在均匀分布的值列表
假设列表中有一个零值:
[0.2, 0.7, 0, 0.5... ]
每两个连续元素平均后,输出列表中得到零元素的概率很小(只有两个连续零导致零)。
这个例子表明,平均将极值推到中心。
我在 windows 7
上使用 python 3.8.5 和 opencv 4.5.1我正在使用以下代码来旋转图像。
def pad_rotate(image, ang, pad, pad_value=0):
(h, w) = image.shape[:2]
#create larger image and paste original image at the center.
# this is done to avoid any cropping during rotation
nH, nW = h + 2*pad, w + 2*pad #new height and width
cY, cX = nW//2, nH//2 #center of the new image
#create new image with pad_values
newImg = np.zeros((h+2*pad, w+2*pad), dtype=image.dtype)
newImg[:,:] = pad_value
#paste new image at the center
newImg[pad:pad+h, pad:pad+w] = image
#rotate CCW (for positive angles)
M = cv2.getRotationMatrix2D(center=(cX, cY), angle=ang, scale=1.0)
rotImg = cv2.warpAffine(newImg, M, (nW, nH), cv2.INTER_CUBIC,
borderMode=cv2.BORDER_CONSTANT, borderValue=pad_value)
return rotImg
我的问题是旋转后,图像强度分布与原始图像不同。
编辑问题的以下部分以澄清问题
img = np.random.rand(500,500)
Rimg = pad_rotate(img, 15, 300, np.nan)
以下是这些图片的样子:
他们的强度明显改变了:
np.percentile(img, [20, 50, 80])
# prints array([0.20061218, 0.50015415, 0.79989986])
np.nanpercentile(Rimg, [20, 50, 80])
# prints array([0.32420028, 0.50031483, 0.67656537])
有人可以告诉我如何避免这种规范化吗?
插值的平均效果改变了分布...
注:
您的代码示例中存在错误(与百分位数无关)。
warpAffine
的第 4 个参数是dst
.
将cv2.warpAffine(newImg, M, (nW, nH), cv2.INTER_CUBIC
替换为:cv2.warpAffine(newImg, M, (nW, nH), flags=cv2.INTER_CUBIC
我尝试简化重现问题的代码示例。
代码示例使用线性插值、1 度旋转且没有 NaN 值。
import numpy as np
import cv2
img = np.random.rand(1000, 1000)
M = cv2.getRotationMatrix2D((img.shape[1]//2, img.shape[0]//2), 1, 1) # Rotate by 1 degree
Rimg = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), flags=cv2.INTER_LINEAR) # Use Linear interpolation
Rimg = Rimg[20:-20, 20:-20] # Crop the part without the margins.
print(np.percentile(img, [20, 50, 80])) #[0.20005696 0.49990526 0.79954818]
print(np.percentile(Rimg, [20, 50, 80])) #[0.32244747 0.4998595 0.67698961]
cv2.imshow('img', img)
cv2.imshow('Rimg', Rimg)
cv2.waitKey()
cv2.destroyAllWindows()
当我们禁用插值时,
Rimg = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]), flags=cv2.INTER_NEAREST)
百分位数是:[0.19943713 0.50004768 0.7995525 ].
显示平均元素改变分布的更简单示例:
A = np.random.rand(10000000)
B = (A[0:-1:2] + A[1::2])/2 # Averaging every two elements.
print(np.percentile(A, [20, 50, 80])) # [0.19995436 0.49999472 0.80007232]
print(np.percentile(B, [20, 50, 80])) # [0.31617922 0.50000145 0.68377251]
为什么插值会使分布偏向中位数?
我不是数学家。
我相信你能得到更好的解释...
这是一个直观的例子:
假设在 [0, 1].
范围内存在均匀分布的值列表
假设列表中有一个零值:
[0.2, 0.7, 0, 0.5... ]
每两个连续元素平均后,输出列表中得到零元素的概率很小(只有两个连续零导致零)。
这个例子表明,平均将极值推到中心。