OpenCV 2 Computer Vision Application Programming Cookbook / Изучаем OpenCV: Играем с изображениями
| Английский оригинал | Перевод на русский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
Эти два примера научат вас создать простой проект с OpenCV, но мы так и не объяснили код OpenCV, который мы использовали. Этот урок покажет вам как использовать наиболее фундаментальные оперторы, которые потребуются для разработки OpenCV приложения. Урок включает загрузку входного изображения из файла, вывод изображения на экран и сохранение выходного изображения на диск. Mellorn 10.08.13 в 18:21 |
|
|
Подготавливаемся oneassasin 03.07.13 в 13:01 |
||
|
Используя MS Visual Studio или Qt, создайте новое консольное приложение с функцией main, которую далее мы заполним. Смотрите первые два пункта, что бы сделать это. oneassasin 18.07.13 в 12:51 |
||
|
Как это сделать... oneassasin 03.07.13 в 13:01 |
||
|
Первое, что необходимо сделать это объявить переменную, которая будет хранить изображение. В OpenCV 2 за это отвечает класс cv::Mat. oneassasin 18.07.13 в 12:53 |
||
|
cv::Mat image; oneassasin 03.07.13 в 13:01 |
||
|
По умолчанию созданное изображение имеет размер 0 на 0 пикселей. Можно вызвать метод size() класса cv::Mat, что-бы получить текущие размеры изображения. Метод вернет структуру, которая будет хранить высоту (height) и ширину (width) изображения: oneassasin 18.07.13 в 12:54 |
||
|
std::cout << "size: " << image.size().height << " , " << image.size().width << std::endl; oneassasin 03.07.13 в 13:01 |
||
|
Следующий шаг - это простой вызов функции, которая считает изображения из файла, декодирует его в понятный компьютеру формат, и разместит в памяти: oneassasin 18.07.13 в 12:55 |
||
|
image = cv::imread("img.jpg"); oneassasin 03.07.13 в 13:01 |
||
|
Теперь можно использовать это изображения. Но, тем не менее, необходимо проверить считалось ли изображение правильно, не возникло ли никаких ошибок при считывании (например, файл не найден, поврежден, или неизвестный формат). Проверка происходит следующим образом: oneassasin 18.07.13 в 12:57 |
||
|
if (!image.data) { oneassasin 03.07.13 в 13:02 |
||
|
Поле data в переменной на самом деле являются указателем на блок памяти, в котором находится изображение. В случае ошибки чтения туда устанавливается 0. Самое простое действие, которое можно сделать с этим изображением - это отобразить его. Для этого необходимо использовать модуль highgui. Прежде всего, необходимо объявить окно, в котором мы хотим отобразить изображение, а потом указать какое изображение мы хотим отобразить в этом окне: oneassasin 18.07.13 в 13:15 |
||
|
cv::namedWindow("Original Image"); // создание окна oneassasin 03.07.13 в 13:02 |
||
|
Теперь можно применить обработчики к этому изображению. OpenCV предлагает много функций обработчиков, и о некоторых из них рассказывается в этой книге. Давайте начнем с простого отображения изображения в горизонтальном отображении. Некоторые трансформации изображений OpenCV могут быть применены на месте, т.е. не прибегая к созданию новой переменной-изображения. Тем не менее, у нас всегда есть возможность создать новую переменную, что бы отобразить изображение, и мы это сделаем: oneassasin 18.07.13 в 13:20 |
||
|
cv::Mat result; oneassasin 03.07.13 в 13:03 |
||
|
И отобразим результат в отдельном окне: oneassasin 18.07.13 в 13:21 |
||
|
cv::namedWindow("Output Image"); oneassasin 03.07.13 в 13:04 |
||
|
Так как это консольное окно завершится вместе с функцией main, то добавим специальный метод модуля highgui для ожидания нажатия пользователем какой нибудь клавиши: oneassasin 18.07.13 в 13:22 |
||
|
cv::waitKey(0); oneassasin 03.07.13 в 13:04 |
||
|
Теперь можно увидеть входящее и выходящее изображение, которые отображены в двух разных окнах. Так же можно сохранить результат обработки (изображение) на жесткий диск в виде файла. Используем функцию модуля highgui для этого: oneassasin 18.07.13 в 13:24 |
||
|
cv::imwrite("output.bmp", result); oneassasin 03.07.13 в 13:04 |
||
|
Расширение файла определяется кодеком, который использовался для сохранения вашего изображения: oneassasin 18.07.13 в 13:25 |
||
|
Как это работает... oneassasin 03.07.13 в 13:04 |
||
|
Все классы и функции определенные в API OpenCV на языке С++ находятся в пространстве имен cv. Есть две возможности доступа к ним. Первый - это определить перед главной функций следующее определение: oneassasin 18.07.13 в 13:45 |
||
|
using namespace cv; oneassasin 03.07.13 в 13:04 |
||
|
Или, использовать ко всем классам и функциям OpenCV префикс cv::, как в этой книге. oneassasin 18.07.13 в 13:46 |
||
|
Класс cv::Mat - это структура данных, которая используется для хранения ваших изображений (и других данных матриц). По умолчанию, он имеет нулевой размер, но можно указать размер при вызове конструктура: oneassasin 18.07.13 в 13:47 |
||
|
cv::Mat ima(240,320,CV_8U,cv::Scalar(100)); oneassasin 03.07.13 в 13:04 |
||
|
В этом случае так же необходимо задать тип каждого элемента матрицы, наше CV_8U в данном случае означает, что каждому пикселю изображения отвечает один байт. Буква U означает беззнаковый. Так же можно объявить числа со знаком используя букву S. Для цветного изображения необходимо использовать три канала (CV_8UC3). Так же можно задать целое число (со знаком или нет) размера 16 и 32 (например, CV_16SC3). Так же есть возможность доступа к 32-х и 64-х битным числам с плавающей точкой (например, CV_32F). oneassasin 18.07.13 в 13:55 |
+2 | |
|
Когда объект cv:Mat выходит из области видения он автоматически удаляется из памяти. Это очень удобно, так как помогает избежать утечек памяти. Так же, класс cv:Mat поддерживает подсчет ссылок, и скрытое копирование когда изображение присваивается другому, тогда две переменных указывают на один и тот же участок памяти с изображением. Подсчет ссылок работает так, что очищает память с изображением, когда больше ничто не указывает на это изображение. Когда вы заходите создать копию оригинального изображения, то используйте метод copyTo(). oneassasin 18.07.13 в 14:01 (продолжение) Вы можете протестировать это поведение, объявив несколько дополнительных изображений в примере этого проекта следующим образом: wuffur 26.08.13 в 19:53 |
||
|
cv::Mat image2, image3; oneassasin 03.07.13 в 13:05 |
||
|
Теперь, если вы ещё раз перевернёте выходное изображение и выведите два дополнительных изображения, то вы увидите, что изображение image2 также пострадало из-за преобразований (потому что указывает на то же изображение, что и результирущее изображение), в то время как image3 остался без изменений, т.е. содержит копию первоначального изображения. Эта распределённая модель для cv::MAT objects , что означает, что вы можете безопасно писать функции (или методы классов) которые будут возвращать изображение: Mellorn 10.08.13 в 18:39 |
||
|
cv::Mat function() { oneassasin 03.07.13 в 13:05 |
||
|
Если мы вызовем эту функцию из нашей главной функции: Mellorn 10.08.13 в 18:27 |
||
|
// получаем изображение в серых тонах oneassasin 03.07.13 в 13:06 |
||
|
Переменная оттенка серого теперь будет содержать изображение сделанное этой функцией без дополнительного выделения памяти. Действительно, только поверхностная копия этого изображения будет передано из возвращенного экземпляра cv::Mat серому изображению. Когда локальная переменная ima выходит из области видимости, она освобождает память (развыделяется), но так как связанная с ней ссылка указывает, что на внешние данные изображение ссылается другой экземпляр (который является переменной оттенка серого), то блок его памяти не освобождается. wuffur 26.08.13 в 19:59 |
||
|
Как бы то ни было, вы должны быть очень осторожны при выборе классов и не возвращать атрибуты класса изображения. Вот пример опасной реализации с ошибкой: Mellorn 10.08.13 в 18:46 |
||
|
class Test { oneassasin 03.07.13 в 13:07 |
||
|
Здесь, если функция вызывает метод этого класса, он получи поверхностную копию атрибутов изображения. Если потом, это копия будет изменена, то атрибут класса также изменится, что может повлиять на последующее поведение этого класса(и наоборот). Чтобы избежать этих ошибок, вам вместо этого нужно вернуть копию этого атрибута. wuffur 26.08.13 в 20:05 |
||
|
Более... oneassasin 03.07.13 в 13:07 И ещё кое-что... wuffur 26.08.13 в 20:01 |
||
|
С появлением версии 2 OpenCV был представлен новый интерфейс. До этого использовались си-подобные функции и структуры(и все ещё могут использоваться. В частности изображениями можно управлять с помощью структуры. Эта структуры наследуется от библиотеки IPL(это Intel Image Processing Library), теперь интегрированная с библиотекой IPP( Intel Integrated Performance Primitive library). Если вы используете код или библиотеки, созданные с помощью старого интерфейса Си, то вам должно быть было необходимо управлять этими структурами IplImage. К счастью существует удобный способ преобразовать структуру IplImage в объект cv::Mat. wuffur 26.08.13 в 20:12 |
||
|
IplImage* iplImage = cvLoadImage("c:\\img.jpg"); oneassasin 03.07.13 в 13:07 |
||
|
Функция cvLoadImage - это функция си-интерфейса для загрузки изображений. Второй параметр конструктор объекта cv::Mat показывает, что данные не будут скопированы (установите его значение true, если вам нужна новая копия, а значение false можно пропустить потому, что но стоит по-умолчанию), тогда и IplImage, и image4 будут разделять между собой одни и те же данные изображения. Вам нужно быть осторожным, если вы не хотите наделать висячих ссылок. По этой причине, безопаснее инкапсулировать указатель IplImage в ссылочный класс считающий указатели, предоставляемый в OpenCV 2: wuffur 26.08.13 в 20:20 |
||
|
cv::Ptr<IplImage> iplImage = cvLoadImage("c:\\img.jpg"); oneassasin 03.07.13 в 13:07 |
||
|
Другими словами, если вам нужно разыменовать указатель на структуру IplImage, тогда вам нужно делать это явно: wuffur 26.08.13 в 20:21 |
||
|
cvReleaseImage(&iplImage); oneassasin 03.07.13 в 13:07 |
||
|
Помните, что вам следует избегать использовать устаревшую структуру данных. Всегда используйте cv::Mat напротив. wuffur 26.08.13 в 20:26 |
||
|
Создание графического интерфейса пользователя GUI с помощью библиотеки Qt wuffur 26.08.13 в 20:26 |
||
|
Qt предоставляет богатую библиотеку, чтобы построить изощрённый графический интерфейс с профессиональным видом. С помощью Qt Creator процесс создания GUI стал простым. Этот рецет покажет вам как построить и создать приложение OpenCV с помощью Qt так, чтобы пользователь мог управлять используя GUI. wuffur 26.08.13 в 20:30 |
