Как преобразовать 8-битный OpenCV IplImage* в 32-битный IplImage*?
Мне нужно конвертировать 8-битный IplImage в 32-битный IplImage. Используя документацию со всего Интернета, я попробовал следующее:
// general code
img2 = cvCreateImage(cvSize(img->width, img->height), 32, 3);
int height = img->height;
int width = img->width;
int channels = img->nChannels;
int step1 = img->widthStep;
int step2 = img2->widthStep;
int depth1 = img->depth;
int depth2 = img2->depth;
uchar *data1 = (uchar *)img->imageData;
uchar *data2 = (uchar *)img2->imageData;
for(h=0;h<height;h++) for(w=0;w<width;w++) for(c=0;c<channels;c++) {
// attempt code...
}
// attempt one
// result: white image, two red spots which appear in the original image too.
// this is the closest result, what's going wrong?!
// see: http://files.dazjorz.com/cache/conversion.png
((float*)data2+h*step2+w*channels+c)[0] = data1[h*step1+w*channels+c];
// attempt two
// when I change float to unsigned long in both previous examples, I get a black screen.
// attempt three
// result: seemingly random data to the top of the screen.
data2[h*step2+w*channels*3+c] = data1[h*step1+w*channels+c];
data2[h*step2+w*channels*3+c+1] = 0x00;
data2[h*step2+w*channels*3+c+2] = 0x00;
// and then some other things. Nothing did what I wanted. I couldn't get an output
// image which looked the same as the input image.
Как вы видите, я действительно не знаю, что я делаю. Я бы с удовольствием узнал, но я бы хотел, чтобы это было сделано правильно. Спасибо за любую помощь, которую я получаю!
6 ответов
Возможно, эта ссылка может помочь вам?
Редактировать В ответ на второе редактирование ОП и комментария
Ты пытался
float value = 0.5
вместо
float value = 0x0000001;
Я думал, что диапазон для значения цвета с плавающей точкой варьируется от 0,0 до 1,0, где 1,0 - белый.
Функция, которую вы ищете - это cvConvertScale(). Это автоматически делает любое преобразование типов для вас. Вам просто нужно указать, что вы хотите масштабировать с коэффициентом 1/255 (который отображает диапазон [0...255] в [0...1]).
Пример:
IplImage *im8 = cvLoadImage(argv[1]);
IplImage *im32 = cvCreateImage(cvSize(im8->width, im8->height), 32, 3);
cvConvertScale(im8, im32, 1/255.);
Обратите внимание на точку в 1/255.
- заставить двойное деление. Без этого вы получите шкалу 0.
Цвета с плавающей запятой изменяются от 0.0 до 1.0, а учёры - от 0 до 255. Следующий код исправляет это:
// h is height, w is width, c is current channel (0 to 2)
int b = ((uchar *)(img->imageData + h*img->widthStep))[w*img->nChannels + c];
((float *)(img2->imageData + h*img2->widthStep))[w*img2->nChannels + c] = ((float)b) / 255.0;
Огромное спасибо Стефану Шмидту за помощь в исправлении этого!
Если вы не поставите точку (.), Некоторые компиляторы поймут, что это деление типа int, что дает вам результат типа int (в данном случае ноль).
Вы можете создать оболочку IplImage, используя boost::shared_ptr и template-metaprogramming. Я сделал это и получаю автоматическую сборку мусора вместе с автоматическим преобразованием изображений из одной глубины в другую или из одноканальных в многоканальные изображения.
Я вызвал API blImageAPI, и его можно найти здесь: http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/
Это очень быстро и делает код очень читабельным (хорошо для поддержки алгоритмов)
Он также может быть использован вместо IplImage в алгоритмах opencv без каких-либо изменений.
Удачи и веселья написание алгоритмов!!!
IplImage * img8, * img32;
img8 = cvLoadImage ("a.jpg", 1);
cvNamedWindow("Convert",1);
img32 = cvCreateImage(cvGetSize(img8),IPL_DEPTH_32F,3);
cvConvertScale(img8,img32,1.0/255.0,0.0);
// Для подтверждения Проверьте значения пикселей (от 0 до 1)
for(int row = 0; row < img32->height; row++ ){
float* pt = (float*) (img32->imageData + row * img32->widthStep);
for ( int col = 0; col < width; col++ )
printf("\n %3.3f , %3.3f , %3.3f ",pt[3*col],pt[3*col+1],pt[3*col+2]);
}
cvShowImage("Convert",img32);
cvWaitKey(0);
cvReleaseImage(&img8);
cvReleaseImage(&img32);
cvDestroyWindow("Convert");