guides:opencv
Original Author: Jacob Haip. Contributions welcome!
Instructions for integrating OpenCV with Folk. This guide involves a manual compilation set outside of folk, but the creation of the wrapper files and the compilation (via an TCL “exec” call) could also be moved within a folk program to completely encapsulate the code.
1. Install OpenCV
sudo apt-get install -y libopencv-dev
2. Create a C wrapper for the OpenCV functions you want to use. I saved these files in a new ~/folk/play/opencv folder.
OpenCVWrapper.h
#ifndef OPENCV_WRAPPER_H #define OPENCV_WRAPPER_H #ifdef __cplusplus extern "C" { #endif typedef struct { uint32_t width; uint32_t height; int components; uint32_t bytesPerRow; uint8_t *data; } cv_image_t; int getWidthOfImage(cv_image_t img); cv_image_t myAdaptiveThreshold(cv_image_t img); #ifdef __cplusplus } #endif #endif // OPENCV_WRAPPER_H
OpenCVWrapper.cpp
#include <opencv2/opencv.hpp> #include <iostream> extern "C" { #include "OpenCVWrapper.h" int getWidthOfImage(cv_image_t img) { return img.width; } cv::Mat convertToMat(const cv_image_t& img) { int type = 0; // Determine the correct type based on number of components if (img.components == 1) { type = CV_8UC1; // Grayscale } else if (img.components == 3) { type = CV_8UC3; // RGB } else { // Add more cases if needed throw std::runtime_error("Unsupported number of components"); } // Create cv::Mat with the given size, type, and data // Note: The step is the number of bytes per row return cv::Mat(img.height, img.width, type, img.data, img.bytesPerRow); } cv_image_t convertToImageT(const cv::Mat& mat) { cv_image_t img; img.width = static_cast<uint32_t>(mat.cols); img.height = static_cast<uint32_t>(mat.rows); int type = mat.type(); if (type == CV_8UC1) { img.components = 1; } else if (type == CV_8UC3) { img.components = 3; } img.bytesPerRow = static_cast<uint32_t>(mat.step); // or mat.step1() // Allocate memory for the data size_t dataSize = mat.step * mat.rows; // or mat.total() * mat.elemSize() img.data = new uint8_t[dataSize]; // Copy the data from the cv::Mat std::memcpy(img.data, mat.data, dataSize); return img; } cv_image_t myAdaptiveThreshold(cv_image_t img) { cv::Mat inputImage = convertToMat(img); cv::Mat outputImage; adaptiveThreshold(inputImage, outputImage, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 11, 2); return convertToImageT(outputImage); } }
3. Compile the wrapper
g++ -fPIC -shared OpenCVWrapper.cpp -o libopencvwrapper.so `pkg-config --cflags --libs opencv4`
4. Use the compiled libopencvwrapper.so and .h file in your folk C code
set cc [c create] defineImageType $cc $cc cflags -I$::env(HOME)/folk/play/opencv $cc include <stdio.h> $cc include "OpenCVWrapper.h" if {[namespace exists ::Heap]} { $cc import ::Heap::cc folkHeapAlloc as folkHeapAlloc $cc import ::Heap::cc folkHeapFree as folkHeapFree } else { $cc code { #define folkHeapAlloc malloc } $cc code { #define folkHeapFree free } } $cc proc opencvAdaptiveThreshold {image_t img} image_t { cv_image_t im2 = (cv_image_t) { .width = img.width, .height = img.height, .components = img.components, .bytesPerRow = img.bytesPerRow, .data = img.data }; cv_image_t r = myAdaptiveThreshold(im2); image_t ret = (image_t) { .width = r.width, .height = r.height, .components = r.components, .bytesPerRow = r.bytesPerRow, .data = folkHeapAlloc(r.bytesPerRow * r.height) }; memcpy(ret.data, r.data, r.bytesPerRow * r.height); return ret; } c loadlib $::env(HOME)/folk/play/opencv/libopencvwrapper.so $cc compile When $this has region /r/ { Claim $this' has region [region move $r down 110%] } set ::opencvOldFrames [list] When $this' has camera slice /slice/ & $this has region /r/ { set grayImg [opencvAdaptiveThreshold $slice] set center [region centroid $r] Wish to draw an image with center $center image $grayImg radians 0 scale 2 lappend ::opencvOldFrames $grayImg if {[llength $::opencvOldFrames] >= 10} { set ::opencvOldFrames [lassign $::opencvOldFrames oldestFrame] image freeImage $oldestFrame } }
guides/opencv.txt · Last modified: 2024/02/02 04:22 by discord