4. OpenCV шаг за шагом. Загрузка картинки


1. OpenCV шаг за шагом. Введение.
2. OpenCV шаг за шагом. Установка.
3. OpenCV шаг за шагом. Hello World.
4. OpenCV шаг за шагом. Загрузка картинки

Продолжим знакомство с OpenCV с простой загрузки картинки из файла.
Этот пример будет основой почти всех будущих программ 🙂

Кстати, чтобы немного развеселить изложение материала рассказ будет вестись от имени знаменитого Чеширского Кота

Думается, что его возможность исчезать будет просто незаменимой для компьютерного зрения 😉

Пррррррррррошу, уважаемый…

Итак, для самого что ни на есть Чеширского OpenCV, рассмотрим простой тестовый пример, который просто выводит картинку, имя которой передано в виде первого параметра программы (если параметров нет — будет пытаться открыть файл Image0.jpg).
Но параметр я разумеется передам и это будет самый Чеширский параметр, а именно моя фотография 🙂

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* image = 0;
IplImage* src = 0;

int main(int argc, char* argv[])
{
	// имя картинки задаётся первым параметром
	char* filename = argc == 2 ? argv[1] : "Image0.jpg";
	// получаем картинку
	image = cvLoadImage(filename,1);
	// клонируем картинку 
	src = cvCloneImage(image);

	printf("[i] image: %s\n", filename);
	assert( src != 0 );

	// окно для отображения картинки
	cvNamedWindow("original",CV_WINDOW_AUTOSIZE);

	// показываем картинку
	cvShowImage("original",image);

	// выводим в консоль информацию о картинке
	printf( "[i] channels:  %d\n",        image->nChannels );
	printf( "[i] pixel depth: %d bits\n",   image->depth );
	printf( "[i] width:       %d pixels\n", image->width );
	printf( "[i] height:      %d pixels\n", image->height );
	printf( "[i] image size:  %d bytes\n",  image->imageSize );
	printf( "[i] width step:  %d bytes\n",  image->widthStep );

	// ждём нажатия клавиши
	cvWaitKey(0);

	// освобождаем ресурсы
	cvReleaseImage(& image);
	cvReleaseImage(&src);
	// удаляем окно
	cvDestroyWindow("original");
	return 0;
}

Результат работы от загрузки моей фотографии:

рассмотрим новые функции, которые использовались в данном примере:

IplImage* cvLoadImage( const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR );

— загружает картинку из файла.
filename — имя файла
iscolor — определяет как представить картинку
iscolor > 0 — цветная картинка с 3-мя каналами
iscolor == 0 — картинка будет загружена в формате GRAYSCALE (градации серого)
iscolor < 0 - картинка будет загружена как есть:

/* 8bit, color or not */
#define CV_LOAD_IMAGE_UNCHANGED  -1
/* 8bit, gray */
#define CV_LOAD_IMAGE_GRAYSCALE   0
/* ?, color */
#define CV_LOAD_IMAGE_COLOR       1
/* any depth, ? */
#define CV_LOAD_IMAGE_ANYDEPTH    2
/* ?, any color */
#define CV_LOAD_IMAGE_ANYCOLOR    4

функция поддерживает следующие форматы изображений:

- Windows bitmaps - BMP, DIB
- JPEG files - JPEG, JPG, JPE
- Portable Network Graphics - PNG
- Portable image format - PBM, PGM, PPM
- Sun rasters - SR, RAS
- TIFF files - TIFF, TIF
IplImage* cvCloneImage( const IplImage* image );

— делает полную копию изображения image, включая заголовок, данные и ROI (Region Of Interest — регион интересов — интересующая область на рисунке).

Обе функции возвращают указатель на картинку IplImage.
Картинка, в OpenCV, представлена структурой вида:

// OpenCV2.0\include\opencv\cxtypes.h
typedef struct _IplImage
{
    int  nSize;             /* sizeof(IplImage) */
    int  ID;                /* version (=0)*/
    int  nChannels;         /* Most of OpenCV functions support 1,2,3 or 4 channels */
    int  alphaChannel;      /* Ignored by OpenCV */
    int  depth;             /* Pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S,
                               IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported.  */
    char colorModel[4];     /* Ignored by OpenCV */
    char channelSeq[4];     /* ditto */
    int  dataOrder;         /* 0 - interleaved color channels, 1 - separate color channels.
                               cvCreateImage can only create interleaved images */
    int  origin;            /* 0 - top-left origin,
                               1 - bottom-left origin (Windows bitmaps style).  */
    int  align;             /* Alignment of image rows (4 or 8).
                               OpenCV ignores it and uses widthStep instead.    */
    int  width;             /* Image width in pixels.                           */
    int  height;            /* Image height in pixels.                          */
    struct _IplROI *roi;    /* Image ROI. If NULL, the whole image is selected. */
    struct _IplImage *maskROI;      /* Must be NULL. */
    void  *imageId;                 /* "           " */
    struct _IplTileInfo *tileInfo;  /* "           " */
    int  imageSize;         /* Image data size in bytes
                               (==image->height*image->widthStep
                               in case of interleaved data)*/
    char *imageData;        /* Pointer to aligned image data.         */
    int  widthStep;         /* Size of aligned image row in bytes.    */
    int  BorderMode[4];     /* Ignored by OpenCV.                     */
    int  BorderConst[4];    /* Ditto.                                 */
    char *imageDataOrigin;  /* Pointer to very origin of image data
                               (not necessarily aligned) -
                               needed for correct deallocation */
}
IplImage;

т.о. вот какую информацию мы получаем в консоли:

image->nChannels // число каналов картинки (RGB, хотя в OpenCV - BGR ) (1-4)
image->depth	// глубина в битах
image->width	// ширина картинки в пикселях 
image->height	// высота картинки в пикселях
image->imageSize // память занимаемая картинкой (==image->height*image->widthStep)
image->widthStep // расстояние между соседними по вертикали точками изображения (число байт в одной строчке картинки
- может потребоваться для самостоятельного обхода всех пикселей изображения)

Пока на этом прервёмся, до встречи уважаемые!

Читать далее: 5. OpenCV шаг за шагом. Вывод видео


50 комментариев на «“4. OpenCV шаг за шагом. Загрузка картинки”»

  1. У меня проблема с загрузкой файла. Почему-то не загружается картинка или видео. cvLoadImage(«pic_my.jpg», 1) возвращает FALSE. В результате получаю окно, залитое просто серым цветом, картинка не отображается. Тоже самое и с видео. Использую версию библиотеки 1.0. Win7. VS2008. В чем может быть дело?

    • странно. возможно не можен найти файл?
      и почему старая версия? попробуйте поработать с OpenCV 2.1

  2. Другая проблема: в filename вписываю изображение формата .tif
    При этом ShowImage отображает серый экран (только окно), но не отображает картинку.

    Как заставить opencv 2.1.0 открывать и работать с .tif?

    • у меня .tif-файлы открывает без проблем.
      Если вы программируете в Visual Studio и запускаете программу не из директории, а прямо из-под IDE (через F5), то картинка должна лежать в директории проекта.

    • функция cvShowImage выдает ошибку при запуске программы F5, если filename = argc == 2? argv[1]: «d:/Program Files/fig.tif»;
      видимо, cvShowImage не работает с tif

      Кроме того, при задании типа TIFF* image = 0 и далее cvShowImage(«original»,image); выдает ошибку, что не может преобразовать TIFF в IplImage.

      Может быть не хватает tif-библиотек или t-f.h или cpp файлов?

    • т.е. файлы другого формата у вас открываются?
      если вы не в Linux-е, нужно писать:

      "d:\\Program Files\\fig.tif"

    • Работаю в Windows XP, Visual Studio 2008. Текст программы в точности повторяет Ваш, я разместил картинку qwe.tif в папке проекта. Вместо image0.jpg написал qwe.TIF.

      При запуске с F5 программа прерывается и в отдельном окне написано: Необработанное исключение в «0x7c812afb» в «01_openimage.exe»: Исключение Microsoft C++: cv::Exception по адресу 0x0011fcb4…

      То же самое пишет, если бы я использовал картинку Image0.jpg, но ее бы не было в папке проекта.

      Пожалуйста, помогите. Очень нужно настроить OpenCV 2.1.0 на открытие и работу с .TIF

      Спасибо

    • только что проделал те же шаги 🙂
      такое исключение вываливается, если не найдена картинка.
      при запуске через F5 картинка должна лежать в папке, где и проектный файл с исходниками.
      Или же проверьте проще — положите картинку в директорию к exe-ку и запустите exe-файл.

    • Код программы: #include «stdafx.h»
      #include <cv.h>
      #include <highgui.h>
      #include <stdlib.h>
      #include <stdio.h>
      #include <tiffio.h>

      IplImage* image = 0;
      IplImage* image2 = 0;
      IplImage* src = 0;
      IplImage* src2 = 0;
      TIFF* imgtiff = 0;

      int main(int argc, char* argv[])
      {
      // имя картинки задаётся первым параметром
      char* filename = argc == 2? argv[1]: «qwe.TIF»;
      char* filename2 = argc == 2? argv[1]: «sf.jpg»;

      // получаем картинку
      image = cvLoadImage(filename,1);
      image2 =cvLoadImage(filename2,1);

      // окно для отображения картинки
      cvNamedWindow(«original»,CV_WINDOW_AUTOSIZE);
      cvNamedWindow(«tiff»,CV_WINDOW_AUTOSIZE);

      // показываем картинку
      cvShowImage(«tiff»,image);
      cvShowImage(«original»,image2);

      // ждём нажатия клавиши
      cvWaitKey(0);

      // освобождаем ресурсы
      cvReleaseImage(&image);
      cvReleaseImage(&image2);
      cvReleaseImage(&src);
      // удаляем окно
      cvDestroyWindow(«original»);
      cvDestroyWindow(«tiff»);
      return 0;
      }

    • Картинки sf.jpg и qwe.TIF лежат во всех возможных папках проекта. При запуске через F5 окно original отображает правильно картинку sf.jpg, а в окне tiff — серый экран (даже форма окна не подстроилась под форму картинки qwe.TIF).

      Я убрал cvCloneImage для картинки qwe.TIF, поскольку с ней выдается вышеописанная ошибка с прерыванием программы.

      cvShowImage почему-то не работает с моим qwe.TIF

    • А как узнать, сколько бит в моем tif файле?

    • Но больше интересует следующее:

      tif-файлы загружаются функцией TIFFOpen или TIFFReadRGBAImage(), а потому объект image должен иметь класс TIFF*, который, в свою очередь, не распознается функцией cvShowImage.

      Все библиотеки tiff для OpenCV имеются у меня в наличии. Вопрос: какая функция заменяет cvShowImage для объектов класса TIFF* и файлов .tif, прикрепленных к ним посредством функции TIFFOpen или TIFFReadRGBAImage()?

      Спасибо.

    • думаю тут два варианта — или посмотреть как это сделано в OpenCV — благо исходники открыты, либо разобраться в формате возвращаемых данных TIFF* и написать функцию-конвертер из TIFF в IplImage

    • сторонней программой. У меня, например, встроенный просмотрщик Total Commader-а выдаёт полную информацию о файле.

    • Спасибо! Попробуем сначала найти аналог cvShowImage для TIFF* в самом OpenCV.

    • Еще раз здравствуйте!

      Я проверил работу вышеописанной программы на двух файлах tif глубиной 1 или 8 бит (черно-белое) или (градации серого). К сожалению, cvShowImage по-прежнему показывает пустое окно.

    • Играясь с преобразователем форматов AbleFaxTifView, я обнаружил, что функция cvShowImage отображает файлы tiff любой глубины, если они не меньше (!) чем 790 байт. Эта граница может быть чуть ниже, я еще не нашел ее минимальное значение, но tiff-файлы размером уже 9 байт не отображаются функцией cvShowImage

    • посредством множества магических манипуляций, я выяснил следующее:

      Картинки, сохраненные из MS Paint или виндового окна «сохранить как» под форматом TIF или TIFF никогда не будут распознаны cvShowImage. Видимо на этом этапе возникают скрытые необратимые преобразования.

      Картинки, приведенные к формату TIF или TIFF из других форматов посредством универсальной программы AbleFaxTifView (доступна в Open Source) могут быть отображены через cvShowImage при любом размере файла или глубине цвета. Полагаю, что через графические редакторы или Photoshop можно вполне безболезненно сохранять картинки в формате TIFF, так что они затем могут быть обработаны cvShowImage.

      Все оказалось довольно нетривиально, но со счастливым концом :). Интересно, почему не работает ситуация из пункта 1, но это предмет дальнейших исследований. А пока начальство может быть спокойно. 🙂

      Всем спасибо!

    • cvShowImage не читает TIFF-файлы, использующие LZW-сжатие.

    • Скажите, пожалуйста. А как можно реализовать следующую ситуацию: Пользователь вводит с клавиатуры путь к картинке, то есть значение filename, а затем программа запускается. Так, чтобы вводить путь не в самой программе.

      Спасибо.

    • 🙂 не вижу проблемы — всё зависит от того — что и как вы реализуете:
      под консоль — просто выводите сообщение и считываете введённую строчку, под win32 — выдаёте окошко для выбора файла.
      Кстати, а как это относится к OpenCV? 😉

    • Я пишу следующее:
      char* filename=0;
      printf(«Insert string: \n»);
      scanf("%s",filename);
      IplImage* image=0;
      image=cvLoadImage(filename,1);

      Не работает. Пишет, что неправильный указатель filename.

    • вы забыли выделить память под буфер filename, в котором собираетесь сохранять введённую строчку.

      char file[1024];
      printf("[c] Insert string: \n");
      scanf("%s", file);
      printf("[i] your string: %s\n", file);

      — обратите внимание, что используется ограниченный по длине массив, по-этому может быть реализовано переполнение буфера (buffer overflow).
      Кстати, Вы не находите, что этот вопрос больше относится к основам программирования C/C++?

    • Спасибо. Но вопрос напрямую касается именно OpenCV. Переменная filename в функции cvLoadImage должна быть типа char* (не массив []), однако я пытаюсь ввести с клавиатуры её значение вручную так:

      char* filename=(char*)calloc(256,sizeof(char));
      scanf(«s%»,filename);
      IplImage* image = cvLoadImage(filename,1);

      сразу после ввода любой строки (ввожу путь к картинке), программа прерывается с ошибкой, что filename — не правильный указатель. Не понятно, функция cvLoadImage требует Массив или символ в качестве filename? Как же тогда сделать ввод строки символов с клавиатуры?

      Спасибо.

    • всего-лишь опечатка (s%)

      char* filename=(char*)calloc(256, sizeof(char));
      scanf("%s",filename);

      а раз мы всё-таки программируем на С++:

      char* filename = new char[1024];
      printf("[c] Insert string: \n");
      scanf("%s", filename);
      printf("[i] your string: %s\n", filename);
      image = cvLoadImage(filename, 1);
    • Ура, спасибо, работает! Вот только ещё стришок бы:

      Если действовать Вашим путем, то приходится все картинки размещать в папке с проектом. А мне хотелось бы вводить путь типа Q:/Program Files/imgs/img1.tiff

      Как только я такой ввожу, программа вылетает (без ошибки :)). Хотя такой путь я могу указать в самой программе, когда объявляю filename, и программа дальше работает, запускает cvLoadImage и всё остальное.

      Такая проблем как-нибудь решается?

      Спасибо.

  3. Скажите пожалуйста, как избавиться от константности указателя filename в функции cvLoadImage(filename, 1) ??

    Мне нужно передать в DLL в качестве этого самого filename строку символов, обозначающую путь к данной картинке, но это приводит к ошибке — «попытка чтения\записи в защищенную память». Нужно убрать свойство const char* filename, и заменить на char* filename. Как это сделать?

    Сама функция cvLoadImage описана в файле loadsave.cpp OpenCV

    Спасибо.

  4. Здравствуйте!

    1. Спасибо за лучшую русскоязычную информацию по opencv.

    2. Возникла проблемма — может что подскажете.
    Столкнулся с тем, что функция cvPyrMeanShiftFiltering корректно работает только в случае входного файла в цветовой гамме sRGB, если же файл в гамме Adobe RGB — функция просто оставляет входное изображение без изменений.
    Какие есть варианты обхода такого поведения?
    Думал о том — что-бы принудительно конвертировать RGB в sRGB, но средствами opencv или pil — не нашел как сделать.
    Спасибо.

    • это уже платформозависимые нюансы. если под Windows, то вместо консольного — создавайте виндовый проект и вперёд.

  5. Здравствуйте, я новенькая в этой сфере… Работаю с студио2010, вот вопрос: допустим у меня есть черно-белое изображение, загрузила и выводится на консоль, все правильно работает… а как считать число белых или черных пикселей на изображение?

    • Спасибо огромное, разбиралась, все понятно стало!!! наконец, после сессии вернулась я сюда! теперь у меня другие проблемы: мне надо построить гистограмму для черно-белой изображении, какую функцию можно тут использовать, с примерами использования если есть

  6. откуда берется картинка? пытаюсь да пытаюсь вывести на экран картинку, но выдает или исключение, или, если закомментить исключение, серый экран. как быть?

    • Если запускаете из-под IDE, то картинка, обычно, должна лежать в каталоге проекта. Впрочем, ничто не мешает прописать абсолютный (полный) путь к файлу картинки.

  7. Всем доброго дня!
    Коллеги, может кто-нибудь объяснить зачем нужна следующая строка кода?

    // клонируем картинку
    src = cvCloneImage(image);

    И почему без этой строки возникает ошибка выполнения?
    Спасибо!

  8. char *imageData;        /* Pointer to aligned image data.         */

    То есть хранит данные цвета в байтовом представлении?? То есть когда первый пиксель изображения красный то первые три char будут 255 0 0?

    • А если мне нужен еще и альфа канал?

    • он может быть четвёртым каналом — BGRA 😉

    • Ясно и надеюсь последний вопрос
      допустим у меня есть bmp изображение в 1 пиксель (0, 255, 0), т.е.

      IplImage* image =  loadImg(full_path);
      ...
      /* получается что
      image->imageData[0] == 0;
      image->imageData[1] == 255;
      image->imageData[2] == 0;
      далее я делаю так
      */
      image->imageData[0] = 181;
      image->imageData[1] = 181;
      image->imageData[2] = 181;
      cvSaveImage(path, image); //возвращает 1
      

      Но на выходе получаю все тот же зеленый пиксель

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Android Arduino Bluetooth CraftDuino DIY IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение