I have written a module called linefind. It works but there are some strange behaviour.
When running on host through jevois-deamon, I get the text "SaveVideo: not recordning" on the output image. I don't write that anywhere in my code. How can it come from another module into mine?
I'm also drawing some dots, but they don't get erased in each frame. Is the image from outframe.get() not blank?
I'm using Jevois 1.8.0 on Ubunto 16.04.
My code is here:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Linefind
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <jevois/Core/Module.H>
#include <jevois/Image/RawImageOps.H>
#include <jevois/Debug/Timer.H>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <jevois/Debug/Log.H>
#include <linux/videodev2.h>
#include <jevois/Util/Utils.H>
#include <jevois/Util/Coordinates.H>
//#include <string.h>
/*
@author Kim Clausen
@videomapping YUYV 320 480 30 YUYV 320 240 30 kimc linefind
@email junktilkim@gmail.com
@restrictions None
*/
class linefind : public jevois::Module
{
public:
//! Default base class constructor ok
using jevois::Module::Module;
//! Virtual destructor for safe inheritance
virtual ~linefind() { }
//! Processing function
virtual void process(jevois::InputFrame && inframe, jevois::OutputFrame && outframe) override
{
static jevois::Timer timer("processing");//, 60, LOG_DEBUG);
// Wait for next available camera image:
jevois::RawImage const inimg = inframe.get(true);
unsigned int const w = inimg.width;
unsigned int const h = inimg.height;
timer.start();
// We only support YUYV pixels in this example, any resolution:
inimg.require("input", w, h, V4L2_PIX_FMT_YUYV);
// Region of interest
cv::Rect roi(20,h-100,w-40,80);
// Convert to OpenCV grayscale:
cv::Mat cvimg = jevois::rawimage::convertToCvGray(inimg);
// Grey
cv::Mat grayimg = cvimg(roi);
// Blur image
cv::Mat blurimg;
cv::GaussianBlur(grayimg, blurimg, cv::Size(3, 3), 8);
// Threshold
cv::Mat thresholdimg;
int retVal = cv::threshold(blurimg, thresholdimg, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
// Edge detection
int rightEdge[roi.height];
int leftEdge[roi.height];
int width[roi.height];
int rightEdgeAvg = 0;
int leftEdgeAvg = 0;
int whitePixels = 0;
for (int j=0; j<roi.height; j++)
{
rightEdge[j] = 0;
leftEdge[j] = 0;
for (int i=0; i<roi.width; i++)
{
cv::Scalar colour = thresholdimg.at<uchar>(cv::Point(i, j));
if(colour.val[0]==255)
{
rightEdge[j] = i;
}
colour = thresholdimg.at<uchar>(cv::Point(roi.width - i, j));
if(colour.val[0]==255)
{
leftEdge[j] = roi.width - i;
}
//count white pixels
colour = thresholdimg.at<uchar>(cv::Point(roi.width - i, j));
if(colour.val[0]==255)
{
whitePixels++;
}
}
rightEdgeAvg += rightEdge[j];
leftEdgeAvg += leftEdge[j];
width[j] = rightEdge[j] - leftEdge[j];
}
rightEdgeAvg = int(rightEdgeAvg / roi.height);
leftEdgeAvg = int(leftEdgeAvg / roi.height);
// Wait for an image from our gadget driver into which we will put our results:
jevois::RawImage outimg = outframe.get();
// Enforce the correct output image size and format:
outimg.require("output", w, h * 2, inimg.fmt);
// Paste original image
//jevois::rawimage::paste(inimg, outimg, 0, 0);
// Let camera know we are done processing the raw YUV input image:
inframe.done();
// Asynchronously launch a bunch of drawings
auto draw_fut =
std::async(std::launch::async, [&]() {
// Draw text
jevois::rawimage::writeText(outimg, "Line Finder", 3, 3, jevois::yuyv::White);
// Draw region of interest
jevois::rawimage::drawRect(outimg, roi.x, roi.y, roi.width, roi.height, jevois::yuyv::White);
// Output images
jevois::rawimage::pasteGreyToYUYV(cvimg, outimg, 0, inimg.height);
jevois::rawimage::pasteGreyToYUYV(thresholdimg, outimg, roi.x, h + roi.y);
//draw detected edges
for (int j=0; j<roi.height; j++)
{
jevois::rawimage::drawDisk(outimg, roi.x + rightEdge[j], roi.y + j, 1, jevois::yuyv::LightGreen);
jevois::rawimage::drawDisk(outimg, roi.x + leftEdge[j], roi.y + j, 1, jevois::yuyv::LightPink);
}
//draw detected edges average
jevois::rawimage::drawDisk(outimg, roi.x + rightEdgeAvg, roi.y + roi.height/2, 5, jevois::yuyv::LightGreen);
jevois::rawimage::drawDisk(outimg, roi.x + leftEdgeAvg, roi.y + roi.height/2, 5, jevois::yuyv::LightPink);
});
// Wait for all drawings to complete:
draw_fut.get();
//sendSerial("L " + std::to_string(rightEdgeAvg) + " " + std::to_string(leftEdgeAvg) + " " + std::to_string(retVal) + " " + std::to_string(whitePixels));
// Send the output image with our processing results to the host over USB:
outframe.send(); // NOTE: optional here, outframe destructor would call it anyway
}
};
// Allow the module to be loaded as a shared object (.so) file:
JEVOIS_REGISTER_MODULE(linefind);