I follow the instruction in this page: http://wiki.elphel.com/index.php?title=OpenCV_Tennis_balls_recognizing_tutorial
to detect the tennis ball. This code may be run for Python and it's requirement is V4L/AVLD for Morphological operations. it's use function cvClose() and cvOpen() to dilate and erode the mask. I write my code in c++, so cvDilate() and cvErode() are used instead, but the result isn't as good as the that site.
Here is my result:output.jpg. (i'm sorry, because i don't have reputation enough to post image T_T)
Here is my full code:
#include "highgui.h"
#include "cv.h"
void main()
{
IplImage* img = cvLoadImage("tennis.jpg",1);
CvSize size = cvGetSize(img);
IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);
cvCvtColor(img, hsv, CV_BGR2HSV);
CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);
cvInRangeS(hsv, cvScalar(0.11*256, 0.60*256, 0.20*256, 0),
cvScalar(0.14*256, 1.00*256, 1.00*256, 0), mask);
cvReleaseImage(&hsv);
IplConvKernel *se21 = cvCreateStructuringElementEx(21, 21, 10, 10, CV_SHAPE_RECT, NULL);
IplConvKernel *se11 = cvCreateStructuringElementEx(11, 11, 5, 5, CV_SHAPE_RECT, NULL);
cvErode(mask, mask, se21);
cvDilate(mask, mask, se11);
cvReleaseStructuringElement(&se21);
cvReleaseStructuringElement(&se11);
/* Copy mask into a grayscale image */
IplImage *hough_in = cvCreateImage(size, 8, 1);
cvCopy(mask, hough_in, NULL);
cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);
/* Run the Hough function */
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq *circles = cvHoughCircles(hough_in, storage,CV_HOUGH_GRADIENT, 4, size.height/10, 100, 40, 0, 0);
cvReleaseMemStorage(&storage);
int i;
for (i = 0; i < circles->total; i++) {
float *p = (float*)cvGetSeqElem(circles, i);
CvPoint center = cvPoint(cvRound(p[0]),cvRound(p[1]));
CvScalar val = cvGet2D(mask, center.y, center.x);
if (val.val[0] < 1) continue;
cvCircle(img, center, 3, CV_RGB(0,255,0), -1, CV_AA, 0);
cvCircle(img, center, cvRound(p[2]), CV_RGB(255,0,0), 3, CV_AA, 0);
cvCircle(mask, center, 3, CV_RGB(0,255,0), -1, CV_AA, 0);
cvCircle(mask, center, cvRound(p[2]), CV_RGB(255,0,0), 3, CV_AA, 0);
}
cvNamedWindow( "Output", CV_WINDOW_AUTOSIZE );
cvShowImage( "Output", img );
cvNamedWindow( "mask", CV_WINDOW_AUTOSIZE );
cvShowImage( "mask", mask );
cvWaitKey(0);
}
Can someone help me to get V4L/AVLD and improve this code ? thank you very much.
V4L/AVLD is for webcam. It doesn't have anything to do with the code or algorithm. http://allonlinux.free.fr/Projets/AVLD/
If you are using Linux, v4l-utls package needs to be installed in order to use webcam.
Related
Recently i switched from opencv-python to c++ version of opencv, because i want to speed up my real time video-processing app with CUDA. I am new to C++ so i found some unclear moments with memory management while optimizing my code.
For example, i have some filter chain like this:
void apply_blue_edgess(cv::Mat& matrix, cv::Mat& mask, cv::Mat& inverted_mask) {
cv::Mat gray_image, blured, canny, canny_3d, in_range_mask;
cv::cvtColor( matrix, gray_image, CV_BGR2GRAY );
cv::GaussianBlur( gray_image, blured, cv::Size( 5, 5 ), 0, 0 );
cv::Canny(blured, canny, 0, 100);
cv::cvtColor( canny, canny_3d, CV_GRAY2BGR );
cv::inRange(canny_3d, cv::Scalar(255,255,255), cv::Scalar(255,255,255), in_range_mask);
canny_3d.setTo(cv::Scalar(0, 171, 255), in_range_mask);
cv::GaussianBlur( canny_3d, matrix, cv::Size( 5, 5 ), 0, 0 );
cv::bitwise_and(matrix, mask, matrix);
}
Is it ok to use new Mat object at every step of the filter chain (gray_image, blured, canny, canny_3d, in_range_mask) ? Is such continuous memory allocation bad for performance? If so, how should i write similar functions?
As was suggested in the comment section, i ended up doing functor wrapper:
struct blue_edges_filter {
blue_edges_filter(int width, int height)
: gray_image(width, height, CV_8UC1),
blured(width, height, CV_8UC1),
canny(width, height, CV_8UC1),
canny_3d(width, height, CV_8UC3),
in_range_mask(width, height, CV_8UC3)
{ }
int operator()(cv::Mat& matrix, cv::Mat& mask, cv::Mat& inverted_mask) {
cv::bitwise_and(matrix, mask, internal_mask_matrix);
cv::bitwise_and(matrix, inverted_mask, external_mask_matrix);
cv::cvtColor( matrix, gray_image, CV_BGR2GRAY );
cv::GaussianBlur( gray_image, blured, cv::Size( 5, 5 ), 0, 0 );
cv::Canny(blured, canny, 0, 100);
cv::cvtColor( canny, canny_3d, CV_GRAY2BGR );
cv::inRange(canny_3d, cv::Scalar(255,255,255), cv::Scalar(255,255,255), in_range_mask);
canny_3d.setTo(cv::Scalar(0, 171, 255), in_range_mask);
cv::GaussianBlur( canny_3d, matrix, cv::Size( 5, 5 ), 0, 0 );
cv::bitwise_and(matrix, mask, matrix);
}
private:
cv::Mat gray_image, blured, canny, canny_3d, in_range_mask;
};
//Usage
blue_edges_filter apply_blue_edgess(1024, 576);
apply_blue_edgess(matrix, mask, inverted_mask);
You can reuse memory without allocation. Create temporal images:
void apply_blue_edgess(cv::Mat& matrix, cv::Mat& mask, cv::Mat& inverted_mask)
{
cv::Mat tmp[2];
int srcInd = 1;
auto InvInd = [&]() -> int { return srcInd ? 0 : 1; };
cv::cvtColor( matrix, tmp[InvInd()], CV_BGR2GRAY );
srcInd = InvInd();
cv::GaussianBlur( tmp[srcInd], tmp[InvInd()], cv::Size( 5, 5 ), 0, 0 );
srcInd = InvInd();
cv::Canny(tmp[srcInd], tmp[InvInd()], 0, 100);
srcInd = InvInd();
cv::cvtColor( tmp[srcInd], tmp[InvInd()], CV_GRAY2BGR );
srcInd = InvInd();
cv::inRange(tmp[srcInd], cv::Scalar(255,255,255), cv::Scalar(255,255,255), tmp[InvInd()]);
tmp[srcInd].setTo(cv::Scalar(0, 171, 255), tmp[InvInd()]);
cv::GaussianBlur( tmp[srcInd], matrix, cv::Size( 5, 5 ), 0, 0 );
cv::bitwise_and(matrix, mask, matrix);
}
I have got bulk of car images and want to perform automatic number plate recognition but i am stuck at localization phase .I want to get license plate individually as output on which i can perform recognition.Here is my code for localization:
int main(int args,char* argv)
{
//String filename;
//filename="";
cv::Mat image=cv::imread("C:\\Users\\Sarora\\Downloads\\Images\\frame_1375.jpg",CV_LOAD_IMAGE_COLOR);
cv::Mat img;
cv::Mat img_sobel;
cv::Mat grad_x, grad_y;
cv::Mat abs_grad_x, abs_grad_y;
cv::Mat imgContours;
//vector <Plate>result;
cv::cvtColor(image, img, CV_BGR2GRAY);
blur(img, img, cv::Size(5,5));
//cv::namedWindow("Img1.jpg", CV_WINDOW_AUTOSIZE );
//sobel filter applied on image..............................................................................................
cv::Sobel(img, grad_x, CV_16S, 1, 0,3,1,0, cv::BORDER_DEFAULT);
convertScaleAbs( grad_x, abs_grad_x );
cv::Sobel(img, grad_y, CV_16S, 0, 1,3,1,0, cv::BORDER_DEFAULT);
convertScaleAbs( grad_y, abs_grad_y );
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, img_sobel );
cv::imwrite("Img2.jpg",img_sobel);
//Threshold the image...................................................................................................................
cv::Mat Thresh_img;
threshold(img_sobel, Thresh_img, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
//imshow("Threshold", Thresh_img);
//Morphological close operation applied................................................................................................
cv::Mat element1=cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
cv::morphologyEx(Thresh_img,Thresh_img,CV_MOP_CLOSE,element1);
cv::imwrite("Close1.jpg",Thresh_img);
//cv::waitKey(5000);
//find Contours of whole image......................................................................................................
std::vector <std::vector<cv::Point>> contours;
cv::findContours(Thresh_img, contours,CV_RETR_LIST,CV_CHAIN_APPROX_NONE);
//cv::drawContours(image,contours,-1,cv::Scalar(0,0,255),3);
cv::imwrite("Contours1.jpg",image);
std::vector <std::vector<cv::Point>>::iterator itc= contours.begin();
std::vector <cv::RotatedRect> rects;
//vector<vector<Point> > contours_poly(rects.size());
//vector<Rect> boundRect(rects.size());
//Remove patch not inside the limits of aspect ratio and area..................................................................................
while (itc!=contours.end()) {
cv::RotatedRect mr= cv::minAreaRect(cv::Mat(*itc));
if( !verifySizes(mr))
{ itc= contours.erase(itc);
}else {
++itc;
rects.push_back(mr);
}
}
cv::Mat drawing;
vector<vector<cv::Point> > contours_poly(rects.size());
vector<cv::Rect> boundRect(rects.size());
//Draw contours
cv::Mat output;
image.copyTo(output);
for(int i=0;i<rects.size();i++)
{
approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 10, true);
boundRect[i] = cv::boundingRect(cv::Mat(contours_poly[i]));
}
//cv::imwrite("Contours.jpg", output);
for (int i = 0; i < rects.size(); i++)
{
drawContours(output, contours_poly, i, CV_RGB(255, 255, 255), 1, 8, vector<cv::Vec4i>(), 0, cv::Point());
//rectangle(output, boundRect[i].tl(), boundRect[i].br(), CV_RGB(0, 255, 0), 3, 8, 0);
}
cv::imwrite("drawing1.jpg",output);
}
bool verifySizes(cv::RotatedRect mr){
float error=0.4;
//Set a min and max area. All other patches are discarded
int min= 5; // minimum area
int max=1000; // maximum area
//Get only patches that match
float rmin= 1;
float rmax= 10;
int area= mr.size.height * mr.size.width;
float r= (float)mr.size.width / (float)mr.size.height;
if(r<1)
r= (float)mr.size.height / (float)mr.size.width;
if(( area < min || area > max ) || ( r < rmin || r > rmax )){
return false;
}else{
return true;
}
}
I have performed sobel filter,Threshold(OTSU+binary),Morphological operation CLOSE,findContours(),removal of one not inside limits of area and aspect ratio and approxPolyDP on the imageThis is my input image
This is approxPolyDP image
Problem is output image is not forming rectangles around License plate.Can anyone tell what is wrong in the code and also how can i proceed further to automatically find license plates in bulk of images?I am confused.
Thank you
Ok, I need to compute the distance between the cap (top of the bottle) and the liquid. I am trying to get the color pixel by pixel from the top down to the liquid. Any ideas how can I do that measure? (I am not sure how to use dilate properly)
#include <opencv/cvaux.h>
#include <opencv/highgui.h>
#include <opencv/cxcore.h>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src = imread("cocaCorte.jpg");
Mat srcTampa, srcLiquido, pixelColor;
Point3_<uchar>* p;
int posicaoX,posicaoY;
void find_moments( Mat grey );
int main(int argc, char* argv[])
{
///Criacao das janelas
cvNamedWindow( "Original", CV_WINDOW_AUTOSIZE);
cvNamedWindow( "Tampa Processada", CV_WINDOW_AUTOSIZE);
cvNamedWindow( "Liquido Processado", CV_WINDOW_AUTOSIZE);
cvNamedWindow( "Bitwise OR", CV_WINDOW_AUTOSIZE);
///Processamento do liquido
inRange( src, Scalar( 0, 0, 0), Scalar( 60, 60, 60), srcLiquido);
GaussianBlur( srcLiquido, srcLiquido, Size( 7, 7), 5, 5);
threshold( srcLiquido, srcLiquido, 100, 255, CV_THRESH_BINARY);
dilate( srcLiquido, srcLiquido, Mat(), Point(-1, -1), 2, 1, 1);
dilate( srcLiquido, srcLiquido, Mat(), Point(-1, -1), 2, 1, 1);
dilate( srcLiquido, srcLiquido, Mat(), Point(-1, -1), 2, 1, 1);
dilate( srcLiquido, srcLiquido, Mat(), Point(-1, -1), 2, 1, 1);
dilate(srcLiquido, srcLiquido, Mat(), Point(-1, -1), 2, 1, 1);
dilate(srcLiquido, srcLiquido, Mat(), Point(-1, -1), 2, 1, 1);
///Processamento da tampa
inRange( src, Scalar( 25, 20, 138), Scalar( 90, 115, 205), srcTampa);
GaussianBlur( srcTampa, srcTampa, Size( 7, 7), 5, 5);
threshold( srcTampa, srcTampa, 100, 255, CV_THRESH_BINARY);
find_moments( srcTampa);
///Juntar as duas imagens
bitwise_or( srcTampa, srcLiquido, pixelColor);
///Calculos
///Reach the white part represent by the liquid starting fromthe top
while(true){
p = pixelColor.ptr<Point3_<uchar> >( posicaoY, posicaoX);
if((p->z=0)&&(p->y=0)&&(p->x=0)){
//that means the liquid was found
break;
}
posicaoY++;
}
cout<<"FOUND"<<endl; //Print the result...
///Mostrar imagens
imshow("Tampa Processada", srcTampa);
imshow("Liquido Processado", srcLiquido);
imshow("Bitwise OR", pixelColor);
waitKey();
destroyAllWindows();
return 0;
}
void find_moments( Mat gray )
{
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using canny
Canny( gray, canny_output, 50, 150, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Get the moments
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
mu[i] = moments( contours[i], false );
}
/// Get the mass centers:
vector<Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 );
}
posicaoX = mc[0].x;
posicaoY = mc[0].y;
/// Draw contours
for( int i = 0; i< contours.size(); i++ )
{
Scalar color = Scalar( 255, 0, 0);
drawContours( src, contours, i, color, 2, 8, hierarchy, 0, Point() );
circle(src, mc[i], 2, color, -1, 1, 0 );
}
/// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", src );
}
Please consider the MWE below. I have a matrix (output) that corresponds to a graphics output buffer and some layers, that should be put into that buffer in a specific order. The layers contain alpha information (last byte). If all layers have the alpha bytes of all pixels set to 0xFF, only the layer on top can be seen. If all have the alpha value set to 0, none can be seen. There can be an alpha value between 0 and 0xFF, so the corresponding pixel should be semi-transparent.
I tried to use addWeighted(), but this didn't help (see below): All images are visible no matter what value the alpha byte is set to.
Do you have any idea how this can be realized?
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
void test(){
namedWindow("window", WINDOW_AUTOSIZE);
Mat output(Size(300, 300), CV_8UC4, Scalar(0));
Mat m1(Size(300, 300), CV_8UC4, Scalar(0));
Mat m2(Size(300, 300), CV_8UC4, Scalar(0));
Mat m3(Size(300, 300), CV_8UC4, Scalar(0));
circle(m1, Point(130, 130), 75, Scalar(0, 0, 0xFF, 0xFF), -1);
circle(m2, Point(150, 150), 75, Scalar(0, 0xFF, 0, 0xFF), -1);
rectangle(m3, Rect(100, 100, 60, 60), Scalar(0xFF, 0, 0, 0xFF), -1);
rectangle(m3, Rect(115, 115, 30, 30), Scalar(0), -1);
/*
Output should look like
[ m3 ] <-- top
[ m2 ]
[ m1 ] <-- bottom
*/
//What I've tried so far (the final solution should work for more than 3 'layers')
m1.copyTo(output);
addWeighted(output, .5, m2, .5, 0, output);
addWeighted(output, .5, m3, .5, 0, output);
imshow("window", output);
cvWaitKey(0);
destroyAllWindows();
}
I'm not sure if this is the best way to do it, but this will maybe do the job.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
using namespace cv;
void addAlpha(Mat src, Mat input);
void test(){
namedWindow("window", WINDOW_AUTOSIZE);
Mat output(Size(300, 300), CV_8UC4, Scalar(0));
Mat m1(Size(300, 300), CV_8UC4, Scalar(0));
Mat m2(Size(300, 300), CV_8UC4, Scalar(0));
Mat m3(Size(300, 300), CV_8UC4, Scalar(0));
circle(m1, Point(130, 130), 75, Scalar(0, 0, 0xFF, 0xFF), -1);
circle(m2, Point(150, 150), 75, Scalar(0, 0xFF, 0, 0xFF), -1);
rectangle(m3, Rect(100, 100, 60, 60), Scalar(0xFF, 0, 0, 0xFF), -1);
rectangle(m3, Rect(115, 115, 30, 30), Scalar(0), -1);
m1.copyTo(output);
addAlpha(output,m2);
addAlpha(output,m3);
imshow("window", output);
cvWaitKey(0);
destroyAllWindows();
}
void addAlpha(Mat src, Mat input){
if(src.rows != input.rows || src.cols != input.cols){
perror("Not same size");
}
for(int i = 0; i < src.rows; i++){
for(int j = 0; j < src.cols; j++){
src.at<cv::Vec4b>(i,j)[0] = src.at<cv::Vec4b>(i,j)[0] * (1 - input.at<cv::Vec4b>(i,j)[3]/255.0) + input.at<cv::Vec4b>(i,j)[0] * (input.at<cv::Vec4b>(i,j)[3]/255.0);
src.at<cv::Vec4b>(i,j)[1] = src.at<cv::Vec4b>(i,j)[1] * (1 - input.at<cv::Vec4b>(i,j)[3]/255.0) + input.at<cv::Vec4b>(i,j)[1] * (input.at<cv::Vec4b>(i,j)[3]/255.0);
src.at<cv::Vec4b>(i,j)[2] = src.at<cv::Vec4b>(i,j)[2] * (1 - input.at<cv::Vec4b>(i,j)[3]/255.0) + input.at<cv::Vec4b>(i,j)[2] * (input.at<cv::Vec4b>(i,j)[3]/255.0);
}
}
}
I hope you could help me.
I' m using QT and try to do a simple detection of edges on a image. But my program crash when i launch
cv::GaussianBlur( src, src, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT );
or
cv::Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, cv::BORDER_DEFAULT );
here is my code:
QImage *image1;
IplImage *cv_image1;
image1 = new QImage("./image.png"); // Format is ARGB32
cv_image1 = QImage2IplImage(image1);
cv::Mat src(cv_image1);
cv::imshow(window_name, src); // Work Well
cv::Mat src_gray;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
cv::GaussianBlur(src, src, cv::Size(3,3), 0, 0, cv::BORDER_DEFAULT); //Crash Here
cv::imshow( window_name, src);
I think that was a problem of format.
But in another program with QIMAGES in ARGB32 this code work well.
Thank you.
Try going with proper QImage to cv::Mat conversion using this functions and you should be fine (I also included a conversion from cv::Mat to QImage):
cv::Mat cvmat_from_qimage(const QImage& qimage)
{
cv::Mat mat = cv::Mat(qimage.height(), qimage.width(), CV_8UC4, (uchar*)qimage.bits(), qimage.bytesPerLine());
cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = { 0,0, 1,1, 2,2 };
cv::mixChannels( &mat, 1, &mat2, 1, from_to, 3 );
return mat2;
}
QImage qimage_from_cvmat(const cv::Mat& mat)
{
cv::Mat rgb;
cvtColor(mat, rgb, CV_BGR2RGB);
return QImage((const unsigned char*)(rgb.data), rgb.cols, rgb.rows, QImage::Format_RGB888);
}
I Found a solution.
That' s weird but when I do:
cvtColor(src, src_gray, CV_RGB2GRAY );
cv::Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, cv::BORDER_CONSTANT);
without the cv::GaussianBlur it works well. I just change the last parameter to cv::BORDER_CONSTANT