I am trying to make this OOP, so I made a class that implements the callback function for the trackbar.
This is my class
class Contours
{
public:
static Mat src_gray;
static int thresh;
Contours(Mat, int);
~Contours(void);
static void callback(int, void* );
private:
};
Contours::Contours(Mat src_gray,int thresh){
this->src_gray=src_gray;
this->thresh=thresh;
}
Contours::~Contours(void){}
void Contours::callback(int, void*)
{int largest_area=0;
int largest_contour_index=0;
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Draw contours
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
cout<<contours.size()<<endl;
for( int i = 0; i< contours.size(); i++ )
{
double a=contourArea( contours[i],false); // Find the area of contour
if(a>largest_area){
largest_area=a;
largest_contour_index=i; } //Store the index of largest contour
//Scalar color = Scalar(255,255,255 );
//drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
}
cout<<"cnt maxim: "<<largest_contour_index<<endl;
Scalar color = Scalar(255,255,255 );
drawContours( drawing, contours, largest_contour_index, color, 2, 8, hierarchy, 0, Point() );
/// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
//imwrite("sada.png",drawing);
}
And calling the function
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, &Contours::callback );
I get
Error 5 error LNK2001: unresolved external symbol "public: static class cv::Mat Contours::src_gray" (?src_gray#Contours##2VMat#cv##A) D:\Licenta\Hand sign recognition\Algoritmi.obj Hand sign recognition
Error 6 error LNK2001: unresolved external symbol "public: static int Contours::thresh" (?thresh#Contours##2HA) D:\Licenta\Hand sign recognition\Algoritmi.obj Hand sign recognition
Any ideas why?
maybe use a different approach to the 'static callback' problem:
class Contours
{
public:
Mat src_gray; // non-static
int thresh;
Contours(Mat, int);
void callback(int, void* ); // non-static
};
void callback(int value, void*ptr) // static global
{
Contours* cnt = (Contours*)ptr; // cast 'this'
cnt->callback(value,0); // call non-static member
}
int main()
{
Mat gray = ...
Contours cnt(gray,17);
// now pass the address of cnt as additional void* Ptr:
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, callback, &cnt );
...
Related
I have an input image:
I use few functions to find contours in this image:
cv::Mat srcImg = cv::imread("input.png");
cv::Mat grayImg{};
cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);
cv::Mat threshImg;
cv::adaptiveThreshold(grayImg, threshImg, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 11, 2);
My picture after thresholding is as below:
Now I want to find contours:
std::vector<std::vector<cv::Point>> ptContours{};
cv::findContours(threshImg, ptContours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
And here is my question: how can I use drawContours() to fill the inner area of the character A?
I want to achieve something like this:
If you get the binary image via Otsu Thresholding, you get a nice binary blob without any "filling problems":
// Read the input image:
std::string imageName = "D://opencvImages//UZUd5.png";
cv::Mat testImage = cv::imread( imageName );
// Convert BGR to Gray:
cv::Mat grayImage;
cv::cvtColor( testImage, grayImage, cv::COLOR_RGB2GRAY );
// Get Binary via Otsu:
cv::Mat binaryImage;
cv::threshold( grayImage, binaryImage, 0, 255, cv::THRESH_OTSU );
This is the result:
If you don't want to use Otsu, and instead use your current approach, this is a possible way of filling the blob. It basically filters every contour by area and hierarchy. I look for the outmost and inmost contours, and perform some flood-fills accordingly - outside of the outer contour, to fill the canvas and inside the inner contour to fill the hole:
// Get Binary via Adaptive Thresh:
cv::Mat binaryImage;
cv::adaptiveThreshold( grayImage, binaryImage, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 11, 2 );
// Containers:
std::vector< std::vector<cv::Point> > contours;
std::vector< cv::Vec4i > hierarchy;
// Create a new matrix where things will be drawn:
cv::Mat filledBlob = cv::Mat::ones( binaryImage.size(), CV_8UC3 );
// Find contours:
cv::findContours(binaryImage, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
// Filling colors:
cv::Scalar fillColor = cv::Scalar( 0,0,0 );
cv::Scalar canvasColor = cv::Scalar( 255,255,255 );
for( int i = 0; i < (int)contours.size(); i++ ){
// Get Blob area:
float blobArea = cv::contourArea( contours[i] );
// Filter smaller blobs:
int minArea = 3000;
if ( blobArea > minArea) {
// Get contour heirarchy:
int contourHierarchy = hierarchy[i][3];
// Process the child contour:
if ( contourHierarchy != -1 ){
// Draw "hole":
cv::drawContours( filledBlob, contours, (int)i, fillColor, 1, cv::LINE_8, hierarchy, 0 );
// Get bounding rectangle:
cv::Rect bBox = cv::boundingRect(contours[i]);
// Compute centroid:
cv::Point centroid;
centroid.x = bBox.x + 0.5*bBox.width;
centroid.y = bBox.y + 0.5*bBox.height;
// Flood-fill at centroid with canvas color:
cv::floodFill( filledBlob, centroid, canvasColor, (cv::Rect*)0, cv::Scalar(), 0);
}else{
// Process the parent contour:
if ( contourHierarchy == -1 ){
// Draw outline:
cv::drawContours( filledBlob, contours, (int)i, fillColor, 1, cv::LINE_8, hierarchy, 0 );
// Flood-fill at canvas (outside of contour):
cv::floodFill( filledBlob, cv::Point( 1, 1 ), canvasColor, (cv::Rect*)0, cv::Scalar(), 0);
}
}
// Show image
cv::imshow( "Filled Blob", filledBlob );
cv::waitKey(0);
}
}
Which yields this image:
If you want an inverted image, just subtract 255 - filledBlob:
cv::subtract( 255, filledBlob, filledBlob );
I'm trying to identify drops on a water-sensitive card, as you can see in the figure below, in addition to the drops there are water risks that I don't want to account for. I'm using OpenCV's findContours function to detect these contours, the question is: can I separate the real drops, from the water drips on the card? Here is an excerpt from my code.
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat src; Mat src_gray; Mat binary_image, goTo;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
cv::Scalar min_color_scanner = Scalar(0,0,0);
cv::Scalar max_color_scanner = Scalar(255,175,210);
int main(int argc, char** argv){
cv::Mat image, gray, thresh;
// MARK:- Load image, grayscale, Otsu's threshold
image = imread("/Users/user/Documents/Developer/Desktop/OpenCV-Teste3.3.1/normal1.png");
Mat circles_detect;
cvtColor( image, circles_detect, CV_BGR2GRAY );
GaussianBlur( circles_detect, circles_detect, Size(9, 9), 2, 2 );
//END CIRCLES
cvtColor(image, gray, CV_BGR2GRAY);
threshold(gray, thresh, 0, 255, THRESH_BINARY_INV + THRESH_OTSU);
Mat mask(image.rows, image.cols, CV_8UC3, Scalar(255,255,255));
cv::Mat bgr_image, inRangeImage;
cv::cvtColor(image, bgr_image, CV_RGB2BGR);
cv::inRange(bgr_image, min_color_scanner, max_color_scanner, binary_image);
//Find contours and filter using contour area
vector<vector<Point>> contours;
cv::findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// MARK:- data from image
double largest_area=0.0;
int largest_contour_index=0;
double smallest_area=0.0;
int smallest_contour_index=0;
int drop_derive=0;
Rect boundig_rect;
for(int i=0;i<contours.size();i++){
double area = contourArea(contours[i]);
if(area > largest_area){
largest_area=area;
largest_contour_index = i;
//boundig_rect = boundingRect(contourArea(contours[i]));
}
}
smallest_area = largest_area;
for(int i=0;i<contours.size();i++){
double area = contourArea(contours[i]);
if(area < smallest_area){
smallest_area=area;
smallest_contour_index = i;
//boundig_rect = boundingRect(contourArea(contours[i]));
}
if (area < 4){
drop_derive++;
cv::drawContours(image, contours, i, Scalar(255,0,0));
}
}
//show datas and images..
return(0);
}
I came across functions used like this:
void func(int, void*);
int main()
{
func(0,0);
}
void func(int, void*)
{
//content
}
And I have no idea, what does it mean. But for some reason, if I copied content from func straight into main, it doesn't work.
I found it used with OpenCV, but no explanation of it.
So I would appreciate, if someone could explain to me what does it mean or why is it used.
So, in my case:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
/// Function header
void thresh_callback(int, void* );
/** #function main */
int main( int argc, char** argv )
{
/// Load source image and convert it to gray
src = imread( "test.png", 1 );
/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, src );
thresh_callback( 0, 0 );
waitKey(0);
return(0);
}
/** #function thresh_callback */
void thresh_callback(int, void* )
{
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Threshold
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
/// Find contours
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Approximate contours to polygons + get bounding rects
vector<vector<Point> > contours_poly( contours.size() );
vector<Rect> boundRect( contours.size() );
for( int i = 0; i < contours.size(); i++ ) {
approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( Mat(contours_poly[i]) );
}
/// Draw bonding rects
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );;
for( int i = 0; i< contours.size(); i++ ) {
rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), Scalar::all(255), 2, 8, 0 );
}
/// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
}
This is code, that I get from the internet. It works well, it detects edges and draw rectangle around them and i can understand it, except declaration of function thresh_callback.
So, my main question is, why it doesn't work without it?
And what does parameters without names mean or why are they there?
1.
void func(int, void*);
declares that there will be a void function called func with two parameters, the first being an int and the second being a void*.
2.
void func(int, void*)
{
//content
}
This is the definition of the function declared in 1. So, if you call func, this function will be executed.
3.
int main()
{
func(0,0);
}
Here you execute func and pass 0 as the first parameter and 0 as the second parameter as well.
4.
If you paste the content of func into main, then it will not work, since the content of func assumes the existence of the two parameters, which do not exist in main.
I want any advice how to solve this Error
I'm trying a sample code to check the opencv_contrib Extra modules using CMake
This is the error message:
And this is the sample code which I used
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
/// Function header
void thresh_callback(int, void*);
/** #function main */
int main(int argc, char** argv)
{
/// Load source image and convert it to gray
src = imread("Baraya.jpg", 1);
/// Convert image to gray and blur it
cvtColor(src, src_gray, CV_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3));
/// Create Window
char* source_window = "Source";
namedWindow(source_window, CV_WINDOW_AUTOSIZE);
imshow(source_window, src);
createTrackbar(" Threshold:", "Source", &thresh, max_thresh, thresh_callback);
thresh_callback(0, 0);
waitKey(0);
return(0);
}
/** #function thresh_callback */
void thresh_callback(int, void*)
{
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Threshold
threshold(src_gray, threshold_output, thresh, 255, THRESH_BINARY);
/// Find contours
findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
/// Approximate contours to polygons + get bounding rects and circles
vector<vector<Point> > contours_poly(contours.size());
vector<Rect> boundRect(contours.size());
vector<Point2f>center(contours.size());
vector<float>radius(contours.size());
for (int i = 0; i < contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
boundRect[i] = boundingRect(Mat(contours_poly[i]));
minEnclosingCircle((Mat)contours_poly[i], center[i], radius[i]);
}
/// Draw polygonal contour + bonding rects + circles
Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
for (int i = 0; i< contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point());
rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0);
circle(drawing, center[i], (int)radius[i], color, 2, 8, 0);
}
/// Show in a window
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawing);
}
There is no error in the code you posted. It works well if you installed OpenCV properly. This error is because you didn't build with any windowing system .
This error is from here:
#if defined (HAVE_WIN32UI) // see window_w32.cpp
#elif defined (HAVE_GTK) // see window_gtk.cpp
#elif defined (HAVE_COCOA) // see window_carbon.cpp
#elif defined (HAVE_CARBON)
#elif defined (HAVE_QT) // see window_QT.cpp
#elif defined (WINRT) && !defined (WINRT_8_0) // see window_winrt.cpp
#else
// No windowing system present at compile time ;-(
//
// We will build place holders that don't break the API but give an error
// at runtime. This way people can choose to replace an installed HighGUI
// version with a more capable one without a need to recompile dependent
// applications or libraries.
void cv::setWindowTitle(const String&, const String&)
{
CV_Error(Error::StsNotImplemented, "The function is not implemented. "
"Rebuild the library with Windows, GTK+ 2.x or Carbon support. "
"If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script");
}
So re-run CMAKE with WITH_WIN32UI, since you are on Windows, and eventually with WITH_QT.
I want to use kinect sdk 2.0 with opencv for shape detection. for that i want to get contour of for the image frame. But i am getting assertion error when I use findcontour function of opencv.
here is the code I used:
void Kinect::ProcessColor(RGBQUAD* pBuffer, int nWidth, int nHeight)
{
// Make sure we've received valid data
if (pBuffer && (nWidth == cColorWidth) && (nHeight == cColorHeight))
{
// Draw the data with OpenCV
Mat ColorImage(nHeight, nWidth, CV_8UC4, pBuffer);
//Mat ColorImage;
//ColorImage = imread("C:/Users/IWP/Desktop/Untitled.png", CV_LOAD_IMAGE_COLOR);
//imshow("ColorImage", ColorImage);
// Convert it to gray
Mat src_gray;
cvtColor(ColorImage, src_gray, CV_BGR2GRAY);
// Canny
Mat src_canny;
Canny(src_gray, src_canny, 75, 125, 3);
//threshold(src_gray, src_canny, 128, 255, CV_THRESH_BINARY);
// find the contours
vector< vector<Point> > contours;
findContours(src_canny, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
Mat showImage;
resize(src_canny, showImage, Size(nWidth / 2, nHeight / 2));
imshow("ColorImage", showImage);////imshow("ColorImage", ColorImage);
}
}