J'utilise un ensemble de données dans lequel il a des images où chaque pixel est un entier non signé de 16 bits stockant la valeur de profondeur de ce pixel en mm. J'essaie de visualiser cela comme une image de profondeur en niveaux de gris en procédant comme suit:
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);
Cependant, il ne montre que deux couleurs, car toutes les valeurs sont proches, c'est-à-dire dans la plage de 150-175 + les petites valeurs qui apparaissent en noir (voir ci-dessous).
Existe-t-il un moyen de normaliser ces données de manière à afficher différents niveaux de gris pour mettre en évidence ces petites différences de profondeur?
Selon la documentation , la fonction imshow peut être utilisée avec une variété de types d'images. Il prend en charge les images non signées 16 bits, vous pouvez donc afficher votre image en utilisant
cv::Mat map = cv::imread("image", CV_LOAD_IMAGE_ANYCOLOR | CV_LOAD_IMAGE_ANYDEPTH);
cv::imshow("window", map);
Dans ce cas, la plage de valeurs d'image est mappée de la plage [0, 255 * 256] à la plage [0, 255].
Si votre image ne contient que des valeurs dans la partie basse de cette plage, vous observerez une image obscure. Si vous souhaitez utiliser la plage d'affichage complète (du noir au blanc), vous devez ajuster l'image pour couvrir la plage dynamique attendue, une façon de le faire est
double min;
double max;
cv::minMaxIdx(map, &min, &max);
cv::Mat adjMap;
cv::convertScaleAbs(map, adjMap, 255 / max);
cv::imshow("Out", adjMap);
En ajoutant à la réponse de samg, vous pouvez étendre encore plus la plage de votre image affichée.
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);
Le résultat devrait être quelque chose comme celui ci-dessous
Si l'entrée imshow
a un type de données à virgule flottante, la fonction suppose que les valeurs des pixels sont dans [0; 1] plage. Par conséquent, toutes les valeurs supérieures à 1 sont affichées en blanc.
Vous n'avez donc pas besoin de diviser votre divisor
par 255.
Ajout à la réponse de Sammy, si la couleur de la plage d'origine est [-min, max] et que vous souhaitez effectuer une égalisation d'histogramme et afficher la couleur de profondeur, le code doit être comme ci-dessous:
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);