我有一個rgb圖像有12種不同的顏色,但我不知道顏色(像素值)事先。我想將0和11之間的所有像素值進行轉換,每個像素都表示原始RGB圖像的獨特顏色。如何將圖像的所有像素值轉換爲一定範圍-python
例如所有[230,100,140]轉換爲[0,0,0],全部[130,90,100]轉換爲[0,0,1]等等...全部[210,80,50]轉換爲[0,0, 11]。
我有一個rgb圖像有12種不同的顏色,但我不知道顏色(像素值)事先。我想將0和11之間的所有像素值進行轉換,每個像素都表示原始RGB圖像的獨特顏色。如何將圖像的所有像素值轉換爲一定範圍-python
例如所有[230,100,140]轉換爲[0,0,0],全部[130,90,100]轉換爲[0,0,1]等等...全部[210,80,50]轉換爲[0,0, 11]。
快速和骯髒的應用程序。許多可以改進,通過像素的整個圖像像素尤其是去是不是很numpy的,也不很OpenCV的,但我懶得準確記得如何閾值和替代RGB像素..
import cv2
import numpy as np
#finding unique rows
#comes from this answer : http://stackoverflow.com/questions/8560440/removing-duplicate-columns-and-rows-from-a-numpy-2d-array
def unique_rows(a):
a = np.ascontiguousarray(a)
unique_a = np.unique(a.view([('', a.dtype)]*a.shape[1]))
return unique_a.view(a.dtype).reshape((unique_a.shape[0], a.shape[1]))
img=cv2.imread(your_image)
#listing all pixels
pixels=[]
for p in img:
for k in p:
pixels.append(k)
#finding all different colors
colors=unique_rows(pixels)
#comparing each color to every pixel
res=np.zeros(img.shape)
cpt=0
for color in colors:
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if (img[i,j,:]==color).all(): #if pixel is this color
res[i,j,:]=[0,0,cpt] #set the pixel to [0,0,counter]
cpt+=1
您可以使用np.unique
帶着幾分權謀:
import numpy as np
def safe_method(image, k):
# a bit of black magic to make np.unique handle triplets
out = np.zeros(image.shape[:-1], dtype=np.int32)
out8 = out.view(np.int8)
# should really check endianness here
out8.reshape(image.shape[:-1] + (4,))[..., 1:] = image
uniq, map_ = np.unique(out, return_inverse=True)
assert uniq.size == k
map_.shape = image.shape[:-1]
# map_ contains the desired result. However, order of colours is most
# probably different from original
colours = uniq.view(np.uint8).reshape(-1, 4)[:, 1:]
return colours, map_
然而,如果像素數比顏色的數量大得多, 以下的啓發式算法可以帶來巨大的速度提升。 它試圖找到一個便宜的散列函數(如只查看紅色通道),如果它成功使用它來創建一個查找表。如果不是,則回到上述安全方法。
CHEAP_HASHES = [lambda x: x[..., 0], lambda x: x[..., 1], lambda x: x[..., 2]]
def fast_method(image, k):
# find all colours
chunk = int(4 * k * np.log(k)) + 1
colours = set()
for chunk_start in range(0, image.size // 3, chunk):
colours |= set(
map(tuple, image.reshape(-1,3)[chunk_start:chunk_start+chunk]))
if len(colours) == k:
break
colours = np.array(sorted(colours))
# find hash method
for method in CHEAP_HASHES:
if len(set(method(colours))) == k:
break
else:
safe_method(image, k)
# create lookup table
hashed = method(colours)
# should really provide for unexpected colours here
lookup = np.empty((hashed.max() + 1,), int)
lookup[hashed] = np.arange(k)
return colours, lookup[method(image)]
測試和定時:
from timeit import timeit
def create_image(k, M, N):
colours = np.random.randint(0, 256, (k, 3)).astype(np.uint8)
map_ = np.random.randint(0, k, (M, N))
image = colours[map_, :]
return colours, map_, image
k, M, N = 12, 1000, 1000
colours, map_, image = create_image(k, M, N)
for f in fast_method, safe_method:
print('{:16s} {:10.6f} ms'.format(f.__name__, timeit(
lambda: f(image, k), number=10)*100))
rec_colours, rec_map_ = f(image, k)
print('solution correct:', np.all(rec_colours[rec_map_, :] == image))
樣本輸出(12種顏色,1000×1000像素):
fast_method 3.425885 ms
solution correct: True
safe_method 73.622813 ms
solution correct: True
safe_method()工作。 fast_method()在第一個for循環中拋出一個錯誤'TypeError:'numpy.ndarray'對象不可調用' –
@FatehSingh嗯,你沒有任何機會影響內建?因爲據我所見,該循環中唯一的函數調用是'range,set,map,tuple'和'len'(我認爲我們可以排除'image.reshape')。你能否檢查一下是否是一個數組。如果是這樣,你應該重新命名該數組。你可以使用'import builtins'獲取內建的數據,然後使用'map = builtins.map'。 –
是的,它的工作原理是名稱碰撞導致問題。謝謝 –
所以首先構造一組的顏色,然後在索引映射它們? –
@Miki:但這不會爲像素分配索引。在這裏你選擇12種顏色。但我們已經知道圖像只包含12種顏色。 –
您想將一個範圍轉換爲另一個範圍。檢查此鏈接:https://stackoverflow.com/questions/929103/convert-a-number-range-to-another-range-maintaining-ratio – zindarod