3 回答

TA貢獻2037條經驗 獲得超6個贊
圖像不同,因為前一個圖像包含浮點數據,而后一個圖像的數據類型是uint8
.
imgc = (imgc * yellow_image)
由于 的數據類型是浮點數,該指令生成一個帶有浮點數數據的新數組yellow_image
。
創建一個yellow_image
with 數據類型uint8
來解決問題:
yellow_image = np.ones(img_paris.shape, dtype=np.uint8) * 255 yellow_image[:,:,0] *= 0 imgc *= yellow_image
或者使用numpy.ndarray.astyp
創建數組的副本并轉換為uint8
:
imgc = (imgc * yellow_image)
imgc = (imgc * yellow_image).astype(np.uint8)
或使用numpy.multiply
, 通過指定轉換規則和類型:
imgc = np.multiply(imgc, yellow_image, casting='unsafe', dtype=np.uint8)

TA貢獻1784條經驗 獲得超7個贊
這兩種技術應該會產生相似的結果。為什么圖像在 for 循環技術中會倒轉?
因為你應該這樣做,轉換數據類型:
imgc = np.uint64(img_paris.copy()) # <-- convert datatype
for x in range(yellow_image.shape[0]):
for y in range(yellow_image.shape[1]):
imgc[x,y] = (imgc[x,y] * yellow_image[x,y])
解釋部分 1 (dtype)
這是因為dtype在重新分配完整矩陣時會發生變化,而在重新分配切片時不會發生:
a = np.array([[1]], np.uint8)
b = np.array([[1]], np.float64)
a[0] = a[0] * b[0] # assigning slices dtype of a does not change
print(a.dtype) #=> uint8
a = a * b # while assigning the full matrix it does
print(a.dtype) #=> float64
如果您dtype一路打印,您會看到:
yellow_image_1 = np.ones(img_paris.shape) * 255
print(yellow_image_1.dtype) #=> float64
yellow_image_1[:,:,0] *= 0
print(yellow_image_1.dtype) #=> float64
imgc_1 = img_paris.copy()
print(imgc_1.dtype) #=> uint8
imgc_1 = (imgc_1 * yellow_image_1)
print(imgc_1.dtype) #=> float64
和這個:
yellow_image_2 = np.ones(img_paris.shape) * 255
print(yellow_image_2.dtype) #=> float64
yellow_image_2[:,:,0] *= 0
print(yellow_image_2.dtype) #=> float64
imgc_2 = img_paris.copy()
print(imgc_2.dtype) #=> uint8
for x in range(yellow_image_2.shape[0]):
for y in range(yellow_image_2.shape[1]):
imgc_2[x,y] = (imgc_2[x,y] * yellow_image_2[x,y])
print(imgc_2.dtype) #=> uint8
所以你最終會得到不同的dtype矩陣。
解釋部分 2 (OpenCV BGR)
如前所述,請記住 OpenCv 使用BGR 格式并且每個像素值從到0,255說np.uint8。
因此,如果您使用的是 matplotlib,為了顯示圖像,您必須交換 B 和 R 通道:
img_paris = cv2.imread('3ClnT.jpg')
plt.imshow(img_paris[:,:,::-1])
如果您使用cv2.imwrite()或cv2imshow()保存,則不需要這樣做,例如:
cv2.imwrite('paris.jpg', img_paris)
也就是說,您可以使用這個線性命令生成純黃色圖像:
yellow_image = np.ones_like(img_paris) * (0, 255, 255)
并顯示或保存它:
plt.imshow(yellow_image[:,:,::-1])
cv2.imwrite('solid_yellow.jpg', yellow_image)
現在,乘法結果的paris_yellow = img_paris * yellow_image值大于255:
[0..1]使用 RGB 數據(對于浮點數或[0..255]整數)將輸入數據剪切到 imshow 的有效范圍。
所以,當你相乘時,你最終得到的最大像素值可以是255 * 255 = 65025.
然后你需要:
將乘法項轉換為支持整數的數據類型65025
乘法后,歸一化然后轉換回uint8
這是一個例子:
paris_yellow_2 = np.int64(img_paris) * np.int64(yellow_image) # <- use int64 terms
max_px_val = np.amax(paris_yellow_2) # <-- Max pixel alue
paris_yellow_2 = np.uint8((paris_yellow_2/max_px_val) * 255) # <- normalize and convert back to uint8
plt.imshow(paris_yellow_2[:,:,::-1])
這是結果:
給出不同結果的其他選項G是將和通道相乘以獲得大于crop 值的R系數。在這種情況下,您需要使用 float :1>255dtype
paris_yellow_3 = np.float64(img_paris) * (1, 3, 3)
paris_yellow_3[paris_yellow_3 > 255] = 255 # <- crops to 255 pixels values > 255
paris_yellow_3 = paris_yellow_3.astype(np.uint8) # <- back to uint8
在這種情況下B,乘以1(不變),G并R乘以3,得到以下結果:

TA貢獻1829條經驗 獲得超13個贊
問題出現在一個完全出乎意料的地方:在創建yellow_image. np.ones默認情況下創建一個浮點類型的數組:因此yellow_image是用浮點類型元素創建的。查看:
>>> yellow_image.dtype
dtype('float64')
因此,當您執行以下操作時:imgc * yellow_image,生成的數組數據類型將提升為精度更高的數據類型(當然是浮點類型),因此imgc具有如下元素:
array([[[ 0., 24225., 12750.],
[ 0., 23715., 12240.],
[ 0., 23460., 11985.],
...,
是浮點型的。
為避免此問題,并且不經歷顯式編寫數據類型的麻煩,請使用:
yellow_image = np.ones_like(img_paris) * 255
np.ones_like創建一個數組,其中包含傳遞給它的數組的形狀,以及完全相同的 dtype - 消除您的后顧之憂?,F在檢查:
>>> yellow_image.dtype
dtype('uint8')
現在考慮imgc1 = imgc * yellow_image和imgc2是循環的輸出。查看:
>>> np.allclose(imgc1, imgc2)
True
問題解決了。
注意- 回答關于為什么圖像倒置的問題:
當乘法結果為浮點類型時,它會將大數字(24225、12750 等)作為像素顏色值。當您使用此數組寫入圖像時,所有這些數字都被裁剪為最大可能的像素顏色值:255。因此,您看到的大部分圖像都是黃色的,因為所有“溢出”值都被裁剪為 255,導致最亮的黃色陰影。
另一方面,當乘法完成強制uint8類型時,任何大于 255 的值都會“回滾”到無符號 8 位整數的最小可能值:0。因此,如果值為 487,dtype 限制將強迫它成為0 + (287 - 255) - 1 = 31。這是溢出。所以很大的數字最終會變得很小——數學很簡單,查一下。因此,您會得到一種倒置的圖像(意外的暗像素)。
添加回答
舉報