亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

常規與使用 For 循環時的 Numpy 數組乘法差異

常規與使用 For 循環時的 Numpy 數組乘法差異

慕蓋茨4494581 2023-02-22 16:30:55
我想在一個完全黃色的圖像上應用乘法混合。圖片是: 巴黎埃菲爾鐵塔黃色圖像是使用以下方法創建的:img_paris = img1 = cv2.imread("/content/drive/My Drive/Datasets/Images/paris.jpg")yellow_image = np.ones(img_paris.shape) * 255 yellow_image[:,:,0] *= 0我嘗試了兩種技術:首先我使用了正則乘法imgc = img_paris.copy()imgc = (imgc * yellow_image)這導致: 埃菲爾成倍增加然后我使用 for 循環來乘以單個元素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])結果是 Eiffel Multiplied 2第二個結果看起來圖像以某種方式倒置了。這兩種技術應該會產生相似的結果。為什么圖像在 for 循環技術中會倒轉?我想使用 For 循環進行更多控制。有人能告訴我為什么會這樣嗎?為什么這兩種技術會導致不同的結果?
查看完整描述

3 回答

?
阿晨1998

TA貢獻2037條經驗 獲得超6個贊

圖像不同,因為前一個圖像包含浮點數據,而后一個圖像的數據類型是uint8.

imgc = (imgc * yellow_image)由于 的數據類型是浮點數,該指令生成一個帶有浮點數數據的新數組yellow_image

創建一個yellow_imagewith 數據類型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)


查看完整回答
反對 回復 2023-02-22
?
嚕嚕噠

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])

這是結果:

http://img1.sycdn.imooc.com//63f5d3060001104f04690352.jpg

給出不同結果的其他選項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,得到以下結果:

http://img1.sycdn.imooc.com//63f5d3100001260f04710351.jpg

查看完整回答
反對 回復 2023-02-22
?
烙印99

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。這是溢出。所以很大的數字最終會變得很小——數學很簡單,查一下。因此,您會得到一種倒置的圖像(意外的暗像素)。


查看完整回答
反對 回復 2023-02-22
  • 3 回答
  • 0 關注
  • 118 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號