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 шаг за шагом. Вывод видео
  • +1
  • 9 июля 2010, 10:10
  • noonv

Комментарии (52)

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

DeVOLT

  • 28 ноября 2010, 18:17
+
0
странно. возможно не можен найти файл?
и почему старая версия? попробуйте поработать с OpenCV 2.1
avatar

noonv

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

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

orcchg

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

noonv

  • 30 ноября 2010, 17:14
+
0
функция 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 файлов?
avatar

orcchg

  • 1 декабря 2010, 13:22
+
0
т.е. файлы другого формата у вас открываются?
если вы не в Linux-е, нужно писать:
"d:\\Program Files\\fig.tif"

avatar

noonv

  • 1 декабря 2010, 13:35
+
0
Работаю в 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

Спасибо
avatar

orcchg

  • 1 декабря 2010, 13:47
+
0
только что проделал те же шаги :)
такое исключение вываливается, если не найдена картинка.
при запуске через F5 картинка должна лежать в папке, где и проектный файл с исходниками.
Или же проверьте проще — положите картинку в директорию к exe-ку и запустите exe-файл.
avatar

noonv

  • 1 декабря 2010, 14:27
+
0
Код программы: #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;
}
avatar

orcchg

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

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

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

orcchg

  • 1 декабря 2010, 16:10
+
0
увы — OpenCV нормально грузит только 8-битные tif-файлы
( https://code.ros.org/trac/opencv/ticket/116 )
только что проверил — это действительно так.
avatar

noonv

  • 1 декабря 2010, 16:27
+
0
А как узнать, сколько бит в моем tif файле?
avatar

orcchg

  • 1 декабря 2010, 16:34
+
0
Но больше интересует следующее:

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

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

Спасибо.
avatar

orcchg

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

noonv

  • 1 декабря 2010, 16:48
+
0
сторонней программой. У меня, например, встроенный просмотрщик Total Commader-а выдаёт полную информацию о файле.
avatar

noonv

  • 1 декабря 2010, 16:45
+
0
Спасибо! Попробуем сначала найти аналог cvShowImage для TIFF* в самом OpenCV.
avatar

orcchg

  • 1 декабря 2010, 16:52
+
0
Еще раз здравствуйте!

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

orcchg

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

orcchg

  • 1 декабря 2010, 17:47
+
0
интересно :)
avatar

noonv

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

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

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

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

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

orcchg

  • 1 декабря 2010, 19:17
+
0
cvShowImage не читает TIFF-файлы, использующие LZW-сжатие.
avatar

orcchg

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

Спасибо.
avatar

orcchg

  • 8 декабря 2010, 18:14
+
0
:) не вижу проблемы — всё зависит от того — что и как вы реализуете:
под консоль — просто выводите сообщение и считываете введённую строчку, под win32 — выдаёте окошко для выбора файла.
Кстати, а как это относится к OpenCV? ;)
avatar

noonv

  • 8 декабря 2010, 18:20
+
0
Я пишу следующее:
char* filename=0;
printf(«Insert string: \n»);
scanf("%s",filename);
IplImage* image=0;
image=cvLoadImage(filename,1);

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

orcchg

  • 8 декабря 2010, 18:24
+
-1
вы забыли выделить память под буфер filename, в котором собираетесь сохранять введённую строчку.
char file[1024];
printf("[c] Insert string: \n");
scanf("%s", file);
printf("[i] your string: %s\n", file);

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

noonv

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

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

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

Спасибо.
avatar

orcchg

  • 8 декабря 2010, 18:51
+
0
всего-лишь опечатка (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);
avatar

noonv

  • 8 декабря 2010, 19:06
+
0
Ура, спасибо, работает! Вот только ещё стришок бы:

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

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

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

Спасибо.
avatar

orcchg

  • 8 декабря 2010, 19:14
+
0
Спасибо за уроки. Весьма полезны.
Можете подсказать, что означают в константах задающих глубину цвета буквы U, S, F?
Точнее, пытаюсь сопоставить IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F и вот это пречисление
avatar

_KoT_

  • 4 января 2011, 18:59
+
0
хм… cvCopyImage в коде нету ни разу, а cvCloneImage — просто для примера :)

чтобы было с чем сравнить :)
фактически, отличий нет — просто перед копированием (cvCopyImage) вам уже нужно создать картинку, а cvCloneImage делает это за вас.

Спасибо! Оперативные консультации — затруднительно :)
avatar

noonv

  • 5 января 2011, 22:30
+
0
Скажите пожалуйста, как избавиться от константности указателя filename в функции cvLoadImage(filename, 1) ??

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

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

Спасибо.
avatar

orcchg

  • 9 января 2011, 12:20
+
0
Здравствуйте!

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

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

avatar

yrik

  • 12 января 2011, 17:58
+
0
Специально для вопросов, напрямую не относящиеся к темам опубликованных статей, запущен форум.
avatar

admin

  • 15 мая 2011, 19:50
+
0
ну дак я использую код с этого поста, и наверное здесь логичней задавать вопрос.
avatar

vomchik

  • 15 мая 2011, 19:53
+
0
А как сделать так, чтобы не открывалась консоль, а только изображение?
avatar

nekitozzz

  • 3 февраля 2013, 12:01
+
0
это уже платформозависимые нюансы. если под Windows, то вместо консольного — создавайте виндовый проект и вперёд.
avatar

noonv

  • 6 февраля 2013, 10:16
+
0
char *imageData;        /* Pointer to aligned image data.         */

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

MrSantiaga

  • 7 марта 2013, 16:38
+
0
именно так. Только, данные хранятся не в формате RGB, а в формате BGR.
avatar

noonv

  • 7 марта 2013, 19:25
+
0
А если мне нужен еще и альфа канал?
avatar

MrSantiaga

  • 14 марта 2013, 16:25
+
0
он может быть четвёртым каналом — BGRA ;)
avatar

noonv

  • 14 марта 2013, 17:22
+
0
Ясно и надеюсь последний вопрос
допустим у меня есть 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

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

MrSantiaga

  • 15 марта 2013, 13:37
+
0
все отбой, причина — кривые руки
avatar

MrSantiaga

  • 15 марта 2013, 17:54
+
0
Здравствуйте, я новенькая в этой сфере… Работаю с студио2010, вот вопрос: допустим у меня есть черно-белое изображение, загрузила и выводится на консоль, все правильно работает… а как считать число белых или черных пикселей на изображение?
avatar

Erkenaz

  • 11 декабря 2014, 20:07
+
0
В принципе, можно обойти пиксели и посчитать «вручную», а если картинка действительно чёрно-белая, то можно использовать мат.-функции cvSum() или даже cvCountNonZero().
avatar

noonv

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

Erkenaz

  • 14 января 2015, 13:55
+
0
см. Histograms
Вопросы, напрямую не относящиеся к статьям, лучше задавать на форуме.
avatar

noonv

  • 15 января 2015, 13:32
+
0
откуда берется картинка? пытаюсь да пытаюсь вывести на экран картинку, но выдает или исключение, или, если закомментить исключение, серый экран. как быть?
avatar

setra2014

  • 18 декабря 2016, 21:00
+
0
Если запускаете из-под IDE, то картинка, обычно, должна лежать в каталоге проекта. Впрочем, ничто не мешает прописать абсолютный (полный) путь к файлу картинки.
avatar

admin

  • 19 декабря 2016, 09:22
+
0
спасибо)
avatar

setra2014

  • 30 декабря 2016, 12:21

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.