2012-12-12 40 views
16

Tôi đang sử dụng tập dữ liệu trong đó có hình ảnh trong đó mỗi pixel là một bit không dấu 16 bit lưu trữ giá trị độ sâu của pixel đó tính bằng mm. Tôi cố gắng để hình dung đây là một hình ảnh sâu xám bằng cách làm như sau:OpenCV: Cách hiển thị hình ảnh độ sâu

cv::Mat depthImage; 
depthImage = cv::imread("coffee_mug_1_1_1_depthcrop.png", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); // Read the file 
depthImage.convertTo(depthImage, CV_32F); // convert the image data to float type 
namedWindow("window"); 
float max = 0; 
for(int i = 0; i < depthImage.rows; i++){ 
    for(int j = 0; j < depthImage.cols; j++){ 
     if(depthImage.at<float>(i,j) > max){ 
      max = depthImage.at<float>(i,j); 
     } 
    } 
} 
cout << max << endl; 


float divisor = max/255.0; 
cout << divisor << endl; 
for(int i = 0; i < depthImage.rows; i++){ 
    for(int j = 0; j < depthImage.cols; j++){ 
     cout << depthImage.at<float>(i,j) << ", "; 
     max = depthImage.at<float>(i,j) /= divisor; 
     cout << depthImage.at<float>(i,j) << endl; 
    } 
} 


imshow("window", depthImage); 
waitKey(0); 

Tuy nhiên, nó chỉ hiển thị hai màu sắc này là bởi vì tất cả các giá trị được gần nhau tức là trong khoảng 150-175 + các giá trị nhỏ hiển thị màu đen (xem bên dưới).

rgb image greyscale image

Có cách nào để chuẩn hóa dữ liệu này như vậy mà nó sẽ hiển thị mức độ xám khác nhau để làm nổi bật những khác biệt sâu nhỏ?

Trả lời

19

Theo documentation, hàm imshow có thể được sử dụng với nhiều loại hình ảnh. Nó hỗ trợ hình ảnh unsigned 16-bit, vì vậy bạn có thể hiển thị hình ảnh của bạn sử dụng

cv::Mat map = cv::imread("image", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH); 
cv::imshow("window", map); 

Trong trường hợp này, phạm vi giá trị hình ảnh được ánh xạ từ khoảng [0, 255 * 256] để khoảng [0, 255] .

Nếu hình ảnh của bạn chỉ chứa các giá trị ở phần thấp của phạm vi này, bạn sẽ quan sát hình ảnh tối nghĩa. Nếu bạn muốn sử dụng phạm vi hiển thị đầy đủ (từ màu đen sang màu trắng), bạn nên điều chỉnh hình ảnh để trang trải các dải động dự kiến, một trong những cách để làm điều đó là

double min; 
double max; 
cv::minMaxIdx(map, &min, &max); 
cv::Mat adjMap; 
cv::convertScaleAbs(map, adjMap, 255/max); 
cv::imshow("Out", adjMap); 
+0

Tôi không thấy lý do tại sao mở rộng nó bằng 255/max (sam như tôi chia tất cả các phần tử bằng max/255) sẽ làm cho nó sử dụng đầy đủ. Ý tôi là, và tôi sẽ chấp nhận câu trả lời nhưng tôi không hiểu. Chức năng đó đang làm gì khác? – Aly

+0

[convertScaleAbs] (http: //docs.opencv.Hàm org/modules/core/doc/operations_on_arrays.html? highlight = convertscaleabs # cv.ConvertScaleAbs) thực hiện 3 thao tác: scale, tính toán giá trị tuyệt đối và chuyển đổi thành kiểu 8 bit không dấu. Đó là lý do tại sao các yếu tố 255/max đảm bảo phạm vi đầy đủ ([0-255] cho unsigned 8-bit) được sử dụng. Hơn nữa, như @sammy đã đề cập, phạm vi động của hình ảnh được điều chỉnh được sử dụng tốt hơn bằng cách tính đến giá trị tối thiểu của dữ liệu của bạn. – samota

2

Nếu đầu vào imshow có loại dữ liệu điểm động thì hàm giả định rằng giá trị pixel nằm trong [0; 1] phạm vi. Kết quả là tất cả các giá trị cao hơn 1 được hiển thị màu trắng.

Vì vậy, bạn không cần phải phân chia của bạn divisor bởi 255.

+0

Sau những dòng này: 'depthImage = cv :: imread ("coffee_mug_1_1_1_depthcrop.png", CV_LOAD_IMAGE_ANY DEPTH | CV_LOAD_IMAGE_ANYCOLOR); depthImage.convertTo (depthImage, CV_32F); 'Nếu tôi in các giá trị nằm trong phạm vi [0,1161] để ước số của tôi là 1161/255 để nhận tất cả các giá trị trong phạm vi [0,255], có lẽ nếu tôi chuyển đổi thành CV_8UC1? – Aly

+0

Ah vâng, điều này đã hiệu quả. Thêm vào đó, nếu tôi sử dụng biểu đồ cân bằng, nó sẽ cho một biểu diễn tốt hơn nhiều – Aly

+0

Đầu tiên, hàm 'imread' đọc bạn hình ảnh giữ nguyên các giá trị ban đầu, vì vậy 1161 là Ok cho 16 bit cho mỗi ảnh pixel. Thứ hai, phương thức 'convertTo' không quy mô giá trị theo mặc định, nó chỉ thay đổi kiểu và saturates. Vì vậy, điều này giải thích tại sao giá trị in quá lớn. –

17

Thêm vào samg' câu trả lời, bạn có thể mở rộng thậm chí nhiều hơn phạm vi của hình ảnh được hiển thị của bạn.

double min; 
double max; 
cv::minMaxIdx(map, &min, &max); 
cv::Mat adjMap; 
// expand your range to 0..255. Similar to histEq(); 
map.convertTo(adjMap,CV_8UC1, 255/(max-min), -min); 

// this is great. It converts your grayscale image into a tone-mapped one, 
// much more pleasing for the eye 
// function is found in contrib module, so include contrib.hpp 
// and link accordingly 
cv::Mat falseColorsMap; 
applyColorMap(adjMap, falseColorsMap, cv::COLORMAP_AUTUMN); 

cv::imshow("Out", falseColorsMap); 

Kết quả sẽ được một cái gì đó như hình dưới đây

enter image description here

+1

có thể cho openCV xuất ra một bản đồ màu với thang đo, như bạn đã thấy ở bên phải không? –

+2

No. Đó là một âm mưu Matlab. – Sam

+0

Chúc mừng Sammy, đánh giá cao phản hồi nhanh chóng –

2

Thêm vào Sammy câu trả lời, nếu màu phạm vi ban đầu là [-min, max] và bạn muốn thực hiện biểu đồ cân bằng và hiển thị màu sâu, mã nên được như dưới đây:

double min; 
double max; 
cv::minMaxIdx(map, &min, &max); 
cv::Mat adjMap; 
// Histogram Equalization 
float scale = 255/(max-min); 
map.convertTo(adjMap,CV_8UC1, scale, -min*scale); 

// this is great. It converts your grayscale image into a tone-mapped one, 
// much more pleasing for the eye 
// function is found in contrib module, so include contrib.hpp 
// and link accordingly 
cv::Mat falseColorsMap; 
applyColorMap(adjMap, falseColorsMap, cv::COLORMAP_AUTUMN); 

cv::imshow("Out", falseColorsMap); 
Các vấn đề liên quan