Настройка GoCV и базовые операции с изображениями
Настройка GoCV и базовые операции с изображениями
Для человека фотография детали на конвейере — это цельный объект. Для компьютера — это просто гигантская таблица чисел, где каждая ячейка описывает цвет одной точки. Чтобы автоматизировать визуальный контроль, поиск дефектов или распознавание текста, нам нужен инструмент, который умеет быстро читать, анализировать и изменять эти таблицы.
В индустрии де-факто стандартом для таких задач является библиотека OpenCV, написанная на C++. Она невероятно быстрая, но писать на C++ скрипты для интеграции с веб-сервисами или базами данных бывает избыточно сложно. Здесь на помощь приходит Go с его простотой и встроенной многопоточностью.
Связующим звеном выступает GoCV — популярная обертка, которая позволяет вызывать мощные алгоритмы OpenCV прямо из кода на Go.
Анатомия цифрового изображения
Прежде чем писать код, нужно понять, с чем именно мы работаем.
Любое изображение состоит из пикселей. Если мы максимально приблизим черно-белую картинку, то увидим сетку, где каждый квадрат имеет свою яркость: от абсолютно черного (значение ) до абсолютно белого (значение ).
В OpenCV эта сетка чисел хранится в специальной структуре данных, которая называется Mat (от слова Matrix — матрица).
Mat — это базовый кирпичик компьютерного зрения. Любое изображение, видеокадр или результат фильтрации всегда представляется в виде объекта
Mat.
Важно сразу запомнить систему координат, с которой работает OpenCV. Она отличается от классической декартовой системы из школьной математики:
- Точка отсчета находится в левом верхнем углу изображения.
- Ось (колонки матрицы) идет слева направо.
- Ось (строки матрицы) идет сверху вниз.
Если размер нашего изображения (ширина 800, высота 600), то правый нижний пиксель будет иметь координаты , .
Установка GoCV
Поскольку GoCV — это мост к C++ библиотеке, обычного go get недостаточно. На вашем компьютере должен быть установлен сам OpenCV и компилятор C++.
Процесс установки зависит от операционной системы, но разработчики GoCV подготовили автоматические скрипты.
- Сначала скачиваем сам пакет GoCV:
go get -u gocv.io/x/gocv - Переходим в директорию скачанного пакета (обычно в
$GOPATH/pkg/mod/gocv.io/x/gocv@...). - Запускаем сборку OpenCV:
- Для Linux / macOS: выполните команду
make install. Скрипт сам скачает исходники OpenCV и скомпилирует их. - Для Windows: выполните
win_build_opencv.cmd. Потребуется установленный компилятор MinGW-w64 и CMake.
- Для Linux / macOS: выполните команду
Примечание: Компиляция OpenCV может занять от 10 до 30 минут в зависимости от мощности процессора.
Чтение и показ изображения
Напишем первую программу. Наша задача — загрузить картинку с диска, показать её в окне и дождаться, пока пользователь нажмет любую клавишу для закрытия.
package main
import (
"fmt"
"gocv.io/x/gocv"
)
func main() {
// 1. Читаем изображение из файла
img := gocv.IMRead("part_123.jpg", gocv.IMReadColor)
// Проверяем, удалось ли прочитать файл
if img.IsEmpty() {
fmt.Println("Ошибка: файл не найден или поврежден")
return
}
// Обязательно освобождаем память C++ при выходе из функции
defer img.Close()
// 2. Создаем окно для показа
window := gocv.NewWindow("Контроль детали")
defer window.Close()
// 3. Показываем матрицу (изображение) в окне
window.IMShow(img)
// 4. Ждем нажатия любой клавиши (0 означает бесконечное ожидание)
window.WaitKey(0)
}
Разберем ключевые моменты:
gocv.IMReadзагружает файл в объектMat. Флагgocv.IMReadColorзаставляет OpenCV прочитать картинку в цвете, даже если исходник был черно-белым (об устройстве цвета мы поговорим в следующей главе).- Метод
.IsEmpty()— стандартный способ проверить корректность загрузки. Если вы укажете неверный путь, программа не упадет с паникой, а просто вернет пустую матрицу. - Управление памятью: объект
Matхранится в памяти, выделенной C++. Сборщик мусора Go не умеет автоматически очищать эту память. Поэтому для каждого созданногоMatмы обязаны вызыватьimg.Close(), иначе в долгоживущем приложении (например, при обработке видеопотока) произойдет утечка памяти.
Обрезка: выделение зоны интереса (ROI)
В задачах автоматизации редко нужно анализировать весь кадр целиком. Если камера фиксирует проезд автомобиля, нас интересует только зона с номером. Если мы проверяем маркировку на микросхеме — нам нужна только поверхность чипа.
Выделение прямоугольного фрагмента матрицы называется получением ROI (Region of Interest — зона интереса).
В GoCV для этого используется стандартная структура image.Rectangle из встроенного пакета Go image. Мы указываем координаты левого верхнего и правого нижнего углов нужной нам зоны.
package main
import (
"image"
"gocv.io/x/gocv"
)
func main() {
img := gocv.IMRead("part_123.jpg", gocv.IMReadColor)
if img.IsEmpty() {
return
}
defer img.Close()
// Определяем прямоугольник: от X=100, Y=50 до X=400, Y=300
cropArea := image.Rect(100, 50, 400, 300)
// Вырезаем зону интереса
croppedImg := img.Region(cropArea)
// croppedImg указывает на ту же память пикселей, что и img!
// Однако метод создает новый заголовок матрицы в C++, поэтому его тоже нужно закрывать.
defer croppedImg.Close()
// Сохраняем результат в новый файл
gocv.IMWrite("defect_zone.jpg", croppedImg)
}
Важное свойство метода .Region(): он не копирует пиксели в новую область памяти. Он создает новый «взгляд» (заголовок матрицы) на ту же самую область памяти исходного изображения. Это делает операцию обрезки мгновенной, что критически важно при обработке видео 60 кадров в секунду. Однако, если вы измените пиксели внутри croppedImg, они изменятся и в оригинальном img.
Мы научились загружать изображение в память, представлять его как матрицу и вырезать нужные фрагменты для дальнейшего анализа. Но пока мы работали с картинкой «как есть». В реальных условиях освещение всегда несовершенно, а детали сливаются с фоном. Чтобы алгоритмы могли находить объекты, исходную матрицу нужно математически преобразовать: убрать лишние цвета, повысить контраст и отфильтровать шум. Этим мы займемся на следующем этапе.