2013-10-17 14 views
6

Tôi đang phát xung quanh với một chiếc máy ảnh cho kính hiển vi sử dụng Micro-Manager 1.4. Sử dụng giao diện Python, tôi đã quản lý để truy cập vào máy ảnh, thay đổi thời gian phơi sáng, vv và tôi có thể chụp các hình ảnh riêng lẻ.Chuyển đổi mảng các pixel số nguyên đơn thành ba rép RGB trong Python

Tuy nhiên, mỗi hình ảnh được trả về dưới dạng mảng NumPy trong đó mỗi pixel được biểu diễn dưới dạng một số nguyên, ví dụ: "7765869". Theo như tôi có thể tìm thấy trên mạng, điều này được biết đến như một "BufferedImage" trong Java, và nó có nghĩa rằng các giá trị RGB được mã hóa như:

BufferedImage = R * 2^16 + G * 2^8 + B 

Câu hỏi của tôi là: Làm thế nào tôi có thể sử dụng ví dụ Numpy hoặc OpenCV, chuyển đổi loại mảng này thành một mảng tiện dụng hơn trong đó mỗi pixel là một bộ ba RGB của các giá trị uint8? Không cần phải nói, việc chuyển đổi phải hiệu quả nhất có thể.

+0

Mở rộng trên lý thuyết đằng sau này một chút, những gì bạn có là một phương trình diophantine tuyến tính có dạng 'một * x + b * y + c * z == n', nơi trong trường hợp của chúng tôi' a = 2 ** 16, b = 2 ** 8, c = 1'. Thông thường, các giải pháp cho các phương trình này liên quan đến việc tìm kiếm 'gcd (a, b, c)' và hy vọng nó chia 'n'; nếu không, thì không có giải pháp. Cho rằng một giải pháp tồn tại, có vô số các giải pháp. Tuy nhiên, chúng ta bị giới hạn trong trường hợp này để tìm ra một giải pháp '0 <= x, y, z <256', do đó sẽ chỉ có một giải pháp cho' gcd (a, b, c) | n'. – wflynny

Trả lời

6

Cách đơn giản nhất là để cho numpy làm việc chuyển đổi cho bạn. Mảng numpy của bạn có lẽ sẽ là loại np.uint32. Nếu bạn xem nó dưới dạng mảng np.uint8, bạn sẽ có định dạng RGB0, tức là giá trị của R, G và B cho mỗi pixel, cộng với một số trống rỗng sau đây là np.uint8. Thật dễ dàng để định hình lại và loại bỏ mà không có giá trị:

>>> img = np.array([7765869, 16777215], dtype=np.uint32) 
>>> img.view(np.uint8) 
array([109, 127, 118, 0, 255, 255, 255, 0], dtype=uint8) 
>>> img.view(np.uint8).reshape(img.shape+(4,))[..., :3] 
array([[109, 127, 118], 
     [255, 255, 255]], dtype=uint8) 

Tốt nhất là không có tính toán hoặc sao chép dữ liệu, chỉ là một lối trình diễn các nội dung của hình ảnh ban đầu của bạn: Tôi không nghĩ rằng bạn có thể nhận được nhiều hơn nữa hiệu quả hơn thế! Tôi nhớ lại rằng đối với một số hoạt động, OpenCV yêu cầu một mảng liền kề, vì vậy bạn có thể phải thêm .copy() vào cuối biểu thức đó để loại bỏ cột số 0, không đơn giản bỏ qua nó, mặc dù điều này tất nhiên kích hoạt bản sao dữ liệu mà mã ở trên đã tránh.

+0

Hoạt động hoàn hảo! Định nghĩa "img2" là "img.view (np.uint8) .reshape (img.shape + (4,)) [...,: 3]" và sau đó sử dụng "cv2.imwrite" hoàn toàn lưu hình ảnh. Cảm ơn! – Bjarke

+0

@Bjarke Bạn có thể muốn chắc chắn rằng bạn đang lưu một hình ảnh RGB, và không phải là một hình ảnh BGR ... Nó sẽ phụ thuộc vào endianess của hệ thống của bạn.Nếu nó sai, chỉ cần gắn '[:: - 1]' vào cuối định nghĩa 'img2' của bạn và nó sẽ đảo ngược thứ tự mà chúng được đọc. – Jaime

+0

Giải pháp rất thông minh! – tom10

0
rgbs = [((x&0xff0000)>>16,(x&0xff00)>>8,x&0xff) for x in values] 

ít nhất tôi nghĩ ...

afaik công thức trên cũng có thể được viết như

BufferedRGB = RED<<16 + GREEN << 8 + BLUE 

red,green,blue = 0xFF,0x99,0xAA 
red<<16 + green << 8 + blue #= 0xFF99AA (buffered into one value) 

#apply a bitmask to get colors back 
red = (0xFF99AA & 0xFF0000) >> 16 # = 0xFF 
green = (0xFF99AA & 0xFF00) >> 8 # = 0x99 
blue = 0xFF99AA & 0xFF   # = 0xAA 

mà là hơi dễ đọc hơn với tôi và rõ ràng những gì đang xảy ra

2

Một chiều là

Red = BufferedImage/2**16 
Green = (BufferedImage % 2**16)/2**8 
Blue = (BufferedImage % 2**8) 

Tuy nhiên, tôi nghi ngờ nó là thanh lịch nhất (Pythonic?) Hoặc là cách nhanh nhất.

0

Cách tiếp cận nhanh nhất có lẽ sẽ là để ghi nhớ điều này NumPy:

from numpy import * 
x = array([211*2**16 + 11*2**8 + 7]) # test data 

b, g, r = bitwise_and(x, 255), bitwise_and(right_shift(x, 8), 255), bitwise_and(right_shift, 16), 255) 

print r, g, b 
(array([211]), array([11]), array([7])) 
Các vấn đề liên quan