Как/Почему imagedata хранится как char - OpenCV

Я немного растерялся.

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

Возможно, стоит отметить, что openCV является библиотекой 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 Результаты неверны. Таким образом, чтобы решить мои проблемы: как я могу работать с данными с целыми числами или с плавающей запятой с помощью указателей char и, в частности, как я могу исправить приведенный выше пример для работы с данными двойной точности.

Спасибо

Ответ 1

  • Изображения
  • IPL_DEPTH_64F или double будут обрабатывать данные от 0 до 1.
  • Если вы привыкли к С++, вы должны проверить OpenCV2.0, который имеет несколько классов С++ и, самое главное, один класс, т.е. 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, имеет смысл:

  • Работайте с указателем double, чтобы вы могли легко назначать элементы в строке ptr[x]
  • Сделайте арифметику указателя в байтах (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)