Го - отличный язык. Он похож на C, но при его использовании вы не чувствуете тяжести истории. Вы можете мгновенно использовать json, карты или параллелизм, настроить и запустить веб-сервер за секунды или даже повторно использовать свой код C из программы Go. Лучше всего то, что строительство и доставка - это несложно.

Но когда вам нужно использовать OpenCV, вы сталкиваетесь с дилеммой. Вы используете OpenCV 2.4, который устарел, но имеет привязки C, поэтому его можно использовать из Go? Или вы используете OpenCV 3, который обновлен с использованием новейших алгоритмов и оптимизаций, но имеет только интерфейс C ++? Если вам нужен OpenCV 3, вы не можете вызвать его напрямую из Go, потому что Go не поддерживает вызовы кода C ++. И, к сожалению, работа над тем, чтобы go-opencv работала с OpenCV 3, похоже, остановлена.

Я провел некоторое тестирование OpenCV 3 на C ++, но я предпочитаю кодировать на Go по нескольким причинам. Для проекта, над которым я сейчас работаю, мне нужно было использовать OpenCV 3. Пора заставить их работать вместе!

Для справки я использовал следующие статьи:

В моем примере кода я открываю видео и показываю его на экране в окне. Все это делается с помощью вызовов OpenCV из C ++. Вот код C ++. Во-первых, мы включаем библиотеки OpenCV и некоторые другие тонкости:

#include <iostream>
#include <unistd.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

Далее воспользуемся небольшим трюком из статьи 2 (вызов C ++ из C):

#ifdef __cplusplus
#define EXTERNC extern “C”
#else
#define EXTERNC
#endif

Теперь мы пишем функцию C ++, которая делает все, что нам нужно, с помощью вызовов OpenCV 3.

EXTERNC void openVideo(char * filename)
{
 VideoCapture cap(filename);
 Mat Uframe;
 int frameCount=0;
 if(!cap.isOpened())
 {
  cout << "Cannot open the video file" << endl;
  return;
 }
 namedWindow("Video", CV_WINDOW_NORMAL);
 while(++frameCount)
 {
  bool bSuccess=cap.read(Uframe);
  if(!bSuccess)
  {
   cout << frameCount << " frames read" << endl;
   break;
  }
  imshow("Video", Uframe);
  waitKey(1);
 }
}

Обратите внимание на следующее:

  • В определении функции используется EXTERNC, чтобы сделать ее вызываемой на C.
  • В этом коде я использую все локальные переменные. Когда вы работаете с несколькими различными функциями, которые используют одни и те же переменные (например, с видеофайлом, который вы открыли, или с матом, содержащим текущий кадр), вам может потребоваться работа с глобальными переменными. Но тогда ваш код нельзя распараллелить с помощью подпрограмм go.
  • Вызов waitKey() необходим, чтобы заставить OpenCV открыть окно и отобразить изображение, как согласно документации OpenCV на imshow().

Затем мы создаем небольшой файл заголовка, чтобы эта функция могла быть вызвана из C. Убедитесь, что файл C ++ имеет расширение .cpp, но файл заголовка имеет расширение .h.

#ifndef OPENCV_IMPLEMENTATION_H
#define OPENCV_IMPLEMENTATION_H
#ifdef __cplusplus
#define EXTERNC extern “C”
#else
#define EXTERNC
#endif
EXTERNC void openVideo(char * filename);
#endif //OPENCV_IMPLEMENTATION_H

Как видите, мы использовали тот же прием, чтобы функция C вызывалась как из C, так и из C ++.

Теперь тяжелая работа сделана! Все, что нам нужно сделать, это написать программу Go для вызова этой функции. Кроме того, для кода Go требуется несколько настроек, чтобы помочь компилятору Go найти наши библиотеки. Для этого нам понадобится import "C", которому предшествуют все параметры компилятора в комментарии Go.

Вот код перехода:

package main
/*
#cgo LDFLAGS: -L/usr/local/Cellar/opencv3/3.2.0/lib -lopencv_core -lopencv_video -lopencv_videoio -lopencv_highgui
#include <stdlib.h>
#include "openCV-implementation.h"
*/
import "C"
func main() {
 theFilename := "Trip-08-48-33.h264"
 C.openVideo(C.CString(theFilename))
}

Несколько замечаний:

  • LDFLAGS содержит все настройки компоновщика. -L добавляет путь к библиотеке для библиотек OpenCV. -l добавляет определенную библиотеку в связанный двоичный файл.
  • Я работаю на Mac и установил OpenCV с помощью Brew. Вот почему библиотеки OpenCV находятся в подкаталоге Cellar. Вы должны заменить это на расположение вашего каталога библиотеки OpenCV.
  • Я добавляю несколько библиотек OpenCV вручную с помощью -lopencv_… Если вам нужно больше или меньше, измените этот список. Посмотрите, какие библиотеки вам нужны, в документации OpenCV.
  • Если вам нужно импортировать другие пакеты Go, используйте отдельную import строку после строки import "C". Строка до import "C" должна быть одной единственной строкой, которая буквально так написана. Если вы объедините импорт C import (...) способом, это не сработает.
  • Я конвертирую строку Go в C *char, используя предоставленную функцию C.Cstring(). Очень кстати!

Вот и все!