Как / Почему изображения хранятся в виде символов - OpenCV - PullRequest
10 голосов
/ 14 ноября 2009

Я немного запутался.

Я только начинаю работать с OpenCV, и на его данные изображения указывает указатель на символ. Я не могу понять, как это работает, учитывая, что фактическими данными могут быть любые типы данных, например. uint, float, double. Насколько я знал, указатель должен быть того же типа, что и указатель, который он представляет.

Вероятно, стоит отметить, что openCV - это библиотека C, а мой фон - C ++, поэтому я не знаю, как эти проблемы с необходимостью типов переменных решаются в C.

Например, следующий код, взятый из Learning OpenCV, иллюстрирует мою путаницу:

void saturate_sv( IplImage* img ) {
    for( int y=0; y<img->height; y++ ) {
    uchar* ptr = (uchar*) (
    img->imageData + y * img->widthStep
    );
       for( int x=0; x<img->width; x++ ) {
           ptr[3*x+1] = 255;
           ptr[3*x+2] = 255;
       }
    }
}

Так что это работает, но когда я пытаюсь работать с iplImage типа IPL_DEPTH_64F и использовать ptr [3 * x + 1] = 1, результаты неверны. Итак, чтобы понять мои проблемы: как я могу работать с целочисленными данными или данными с плавающей запятой через указатели на символы и, в частности, как я могу исправить приведенный выше пример для работы с данными двойной точности.

Спасибо

1 Ответ

16 голосов
/ 14 ноября 2009
  1. IPL_DEPTH_64F или double изображения позаботятся о данных от 0 до 1.
  2. Если вы привыкли к C ++, вы должны проверить OpenCV2.0 , который имеет несколько классов C ++ и, что наиболее важно, один класс, т.е. Mat для обработки изображений, матриц и т. Д.

Вот простой способ эффективного доступа к элементам в вашем изображении:

IplImage* img = cvCreateImage(cvSize(300,300),IPL_DEPTH_64F,1);
for( int y=0; y<img->height; y++ ) 
    {
       double* ptr = reinterpret_cast<double*>(img->imageData + y * img->widthStep);
       for( int x=0; x<img->width; x++ ) 
       {
          ptr[x] = double(255);
       }
    }
cvNamedWindow("SO");
cvShowImage("SO",img);
cvWaitKey();
cvDestroyAllWindows();
cvReleaseImage(&img);

Поскольку вы работаете с double изображением, имеет смысл:

  1. Работайте с указателем double, чтобы вы могли легко назначать элементы в строке с помощью ptr[x]
  2. Выполните арифметику указателя в байтах (img->imageData + y * img->widthStep) и приведите его к double указателю

Кроме того, важно делать арифметику указателей в байтах (или uchar, т.е. unsigned char), поскольку OpenCV имеет тенденцию заполнять строки изображений дополнительными байт для эффективности (особенно для double изображений).

Таким образом, даже если элемент double имеет длину 8 байтов, а у вас, скажем, 300 строк, строка не обязательно заканчивается на 8 * 300 или 2400 байтах, поскольку OpenCV может дополнить конец.

Следовательно, это предотвращает инициализацию указателя на первый элемент изображения и последующее использование ptr[y*img->height+x] для доступа к элементам, поскольку каждая строка может иметь более 8*(y*img->height) байтов.

Это , поэтому пример кода вычисляет указатель на каждую строку каждый раз, используя img->widthStep, который представляет истинный размер каждой строки в байтах.

OpenCV 2.0

Если вы используете класс Mat, вы можете сделать то же самое по следующим направлениям:

cv::Mat img(300,300,CV_64FC1);
for( int y=0; y<img.rows; y++ ) 
    {
       double* ptr = reinterpret_cast<double*>(img.data + y * img.step);
       for( int x=0; x<img.cols; x++ ) 
       {
          ptr[x] = double(255);
       } 
    }
cv::namedWindow("SO");
cv::imshow("SO",img);
cv::waitKey();

где img.step - расстояние между последовательными строками в байтах

А если вы хотите получить прямой доступ к элементу (медленнее):

img.at<double>(y,x)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...