I have a program that creates boxes of car plates.
Input1:
Output1:
Input2:
Output2:
Code:
#include <cv.h> // open cv general include file
#include <highgui.h> // open cv GUI include file
#include <iostream> // standard C++ I/O
#include <vector>
#include <list>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <regex>
#include <string>
#include <fstream>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
Mat img;
int largest_area=0;
int largest_contour_index=0;
Rect bounding_rect;
img = imread( argv[1], 1 );
Mat tmp = img;
cvtColor( img, img, CV_BGR2GRAY );
GaussianBlur(img, img, Size(5,5), 0);
threshold(img, img, 0, 255, CV_THRESH_OTSU);
Mat temp(img.rows,img.cols,CV_8UC1);
Mat dst(img.rows,img.cols,CV_8UC1,Scalar::all(0));
img.copyTo(temp);
vector<vector<Point>> contours; // storing contour
vector<Vec4i> hierarchy;
findContours( temp, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
for( int i = 0; i< contours.size(); i++ ) // iterate
{
double a=contourArea( contours[i],false); //Find the largest area of contour
if(a>largest_area)
{
largest_area=a;
largest_contour_index=i;
bounding_rect=boundingRect(contours[largest_contour_index]); // Find the bounding rectangle for biggest contour
}
}
drawContours( dst, contours,largest_contour_index, Scalar(255), CV_FILLED, 8, hierarchy );
rectangle(tmp, bounding_rect, Scalar(255,255,255),1, 8,0);
Mat roi = tmp(bounding_rect);
imshow("Final", roi);
waitKey();
return(0);
}
Do you know how to compare the license plate to be straight? Or another approach to create these boxes?
Here's my test set: http://www.filedropper.com/carboxtar
Related
I'm working on a project to detect motion on a camera.
I need to start recording video when motion is detected for example:
Record while motion is being detected
Continue recording for 10 seconds after the motion detection is stopped
I have a working example that only detects the motion and draw rectangles on the moving parts.
I searched for examples on how to record when motion is detected but no good results.
Here is my working code:
#include <iostream>
#include <sstream>
#include <opencv4/opencv2/imgproc.hpp>
#include <opencv4/opencv2/videoio.hpp>
#include <opencv4/opencv2/highgui.hpp>
#include <opencv4/opencv2/video.hpp>
#include <unistd.h>
using namespace cv;
using namespace std;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
int main(int argc, char* argv[])
{
//create Background Subtractor objects
Ptr<BackgroundSubtractor> pBackSub;
pBackSub = createBackgroundSubtractorMOG2();
VideoCapture capture(0);
if (!capture.isOpened()){
//error in opening the video input
cerr << "Unable to open: " << endl;
return 0;
}
Mat frame, fgMask;
sleep(3);
while (true) {
capture >> frame;
if (frame.empty())
break;
//update the background model
pBackSub->apply(frame, fgMask);
imshow("FG Mask", fgMask);
RNG rng(12345);
findContours(fgMask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0, 0));
vector<Rect>boundRect (contours.size());
vector<vector<Point> > contours_poly( contours.size() );
for (int i = 0; i < contours.size();i++) {
if( contourArea(contours[i])< 500)
{
continue;
}
putText(frame, "Motion Detected", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
approxPolyDP( contours[i], contours_poly[i], 3, true );
boundRect[i] = boundingRect( contours_poly[i] );
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
rectangle( frame, boundRect[i].tl(), boundRect[i].br(), color, 2 );
}
imshow("Frame", frame);
int keyboard = waitKey(30);
if (keyboard == 'q' || keyboard == 27)
break;
}
return 0;
}
I tried adding this to the code:
int frameWidth = 320;
int frameHeight = 240;
cv::Size frameSize = cv::Size(frameWidth, frameHeight);
/* Output file */
int codec = cv::VideoWriter::fourcc('M', 'P', '4', 'V');
cv::VideoWriter outputVideo;
outputVideo.open("rr.mp4", codec, capture.get(cv::CAP_PROP_FPS), frameSize, true);
and after drawing the rectangle I write the frame to the video:
outputVideo.write(frame);
but after that, the video is empty and crashes.
I already took a look at Motion but I didn't find an example.
How can I achieve this?
Thanks,
Talel
I resolved the issue,
I was opening the output video with a specific dimensions (320,240) and I was saving the captured frame which is bigger.
So the solution is to resize the captured frame to fit into the output video.
Here is the final solution if anyone is interesting:
Turn the laptop camera into an IP camera with: cam2ip
Here is the source code:
#include <iostream>
#include <sstream>
#include <opencv4/opencv2/imgproc.hpp>
#include <opencv4/opencv2/videoio.hpp>
#include <opencv4/opencv2/highgui.hpp>
#include <opencv4/opencv2/video.hpp>
#include <unistd.h>
using namespace cv;
using namespace std;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
int main(int argc, char* argv[])
{
//create Background Subtractor objects
Ptr<BackgroundSubtractor> pBackSub;
pBackSub = createBackgroundSubtractorMOG2();
const std::string videoStreamAddress = "http://192.168.20.100:56000/mjpeg";
cv::VideoCapture vcap;
if(!vcap.open(videoStreamAddress)) {
std::cout << "Error opening video stream or file" << std::endl;
return -1;
}
Mat frame, fgMask;
int frameWidth = 320;
int frameHeight = 240;
cv::Size frameSize = cv::Size(frameWidth, frameHeight);
/* Output file */
int codec = cv::VideoWriter::fourcc('M', 'P', '4', 'V');
cv::VideoWriter outputVideo;
outputVideo.open("rr.mp4", codec, vcap.get(cv::CAP_PROP_FPS), frameSize, true);
sleep(3);
while (true) {
vcap >> frame;
if (frame.empty())
break;
//update the background model
pBackSub->apply(frame, fgMask);
imshow("FG Mask", fgMask);
RNG rng(12345);
findContours(fgMask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point(0, 0));
vector<Rect>boundRect (contours.size());
vector<vector<Point> > contours_poly( contours.size() );
for (int i = 0; i < contours.size();i++) {
if( contourArea(contours[i])< 500)
{
continue;
}
putText(frame, "Motion Detected", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
approxPolyDP( contours[i], contours_poly[i], 3, true );
boundRect[i] = boundingRect( contours_poly[i] );
Scalar color = Scalar( rng.uniform(0, 256), rng.uniform(0,256), rng.uniform(0,256) );
rectangle( frame, boundRect[i].tl(), boundRect[i].br(), color, 2 );
resize(frame, frame, frameSize);
outputVideo.write(frame);
}
imshow("Frame", frame);
int keyboard = waitKey(30);
if (keyboard == 'q' || keyboard == 27)
break;
}
outputVideo.release();
return 0;
}
Further enhancement suggestions:
Make sure that the light is not part of the motion detection
Open an output video with the same capture's dimensions
I am using cascade for detection object and I want to save my video after detection But I can save just a frame (I can save just the last frame)
And my code is here:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <opencv2/objdetect/objdetect.hpp>
using namespace std;
using namespace cv;
int main()
{
CascadeClassifier nesne;
nesne.load("cascade.xml");
string filename = "a.avi";
VideoCapture capture(filename);
Mat frame;
Mat grires;
namedWindow("algilanan", 1);
while(true)
{
capture>>frame;
cvtColor(frame, grires, CV_BGR2GRAY); //resmi gri renk uzayına çevirir.
vector<Rect> nesvek;
nesne.detectMultiScale(grires, nesvek, 1.1, 3, 0, Size(30,30));
for(int i = 0; i < nesvek.size(); i++)
{
Point pt1(nesvek[i].x + nesvek[i].width, nesvek[i].y + nesvek[i].height);
Point pt2(nesvek[i].x, nesvek[i].y);
rectangle(frame, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8, 0);
}
int frame_width= capture.get(CV_CAP_PROP_FRAME_WIDTH);
int frame_height= capture.get(CV_CAP_PROP_FRAME_HEIGHT);
VideoWriter video("out.avi",CV_FOURCC('M','J','P','G'),10, Size(frame_width,frame_height),true);
video.write(frame);
imshow("algilanan", frame);
waitKey(33);
}
return 0;
}
The reason you can save a single frame is because you are re-initializing the VideoWriter on every iteration of the loop. You should initialize it outside the loop. Try this.
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <opencv2/objdetect/objdetect.hpp>
using namespace std;
using namespace cv;
int main()
{
CascadeClassifier nesne;
nesne.load("cascade.xml");
string filename = "a.avi";
VideoCapture capture(filename);
Mat frame;
Mat grires;
namedWindow("algilanan", 1);
int frame_width= capture.get(CV_CAP_PROP_FRAME_WIDTH);
int frame_height= capture.get(CV_CAP_PROP_FRAME_HEIGHT);
VideoWriter video("out.avi",CV_FOURCC('M','J','P','G'),10,Size(frame_width,frame_height),true);
while(true)
{
capture>>frame;
cvtColor(frame, grires, CV_BGR2GRAY); //resmi gri renk uzayına çevirir.
vector<Rect> nesvek;
nesne.detectMultiScale(grires, nesvek, 1.1, 3, 0, Size(30,30));
for(int i = 0; i < nesvek.size(); i++)
{
Point pt1(nesvek[i].x + nesvek[i].width, nesvek[i].y + nesvek[i].height);
Point pt2(nesvek[i].x, nesvek[i].y);
rectangle(frame, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8, 0);
}
video.write(frame);
imshow("algilanan", frame);
waitKey(33);
}
return 0;
}
I have found a program which can binarize an image and make the image monochrome
OpenCV Adaptive Threshold OCR
I have copy/pasted the code
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdarg.h>
#include "/usr/include/opencv2/opencv.hpp"
#include "fstream"
#include "iostream"
using namespace std;
using namespace cv;
void CalcBlockMeanVariance(Mat& Img,Mat& Res,float blockSide=21) // blockSide - the parameter (set greater for larger font on image)
{
Mat I;
Img.convertTo(I,CV_32FC1);
Res=Mat::zeros(Img.rows/blockSide,Img.cols/blockSide,CV_32FC1);
Mat inpaintmask;
Mat patch;
Mat smallImg;
Scalar m,s;
for(int i=0;i<Img.rows-blockSide;i+=blockSide)
{
for (int j=0;j<Img.cols-blockSide;j+=blockSide)
{
patch=I(Range(i,i+blockSide+1),Range(j,j+blockSide+1));
cv::meanStdDev(patch,m,s);
if(s[0]>0.01) // Thresholding parameter (set smaller for lower contrast image)
{
Res.at<float>(i/blockSide,j/blockSide)=m[0];
}else
{
Res.at<float>(i/blockSide,j/blockSide)=0;
}
}
}
cv::resize(I,smallImg,Res.size());
cv::threshold(Res,inpaintmask,0.02,1.0,cv::THRESH_BINARY);
Mat inpainted;
smallImg.convertTo(smallImg,CV_8UC1,255);
inpaintmask.convertTo(inpaintmask,CV_8UC1);
inpaint(smallImg, inpaintmask, inpainted, 5, INPAINT_TELEA);
cv::resize(inpainted,Res,Img.size());
Res.convertTo(Res,CV_32FC1,1.0/255.0);
}
int main( int argc, char** argv )
{
namedWindow("Img");
namedWindow("Edges");
//Mat Img=imread("D:\\ImagesForTest\\BookPage.JPG",0);
Mat Img=imread("Test2.JPG",0);
Mat res;
Img.convertTo(Img,CV_32FC1,1.0/255.0);
CalcBlockMeanVariance(Img,res);
res=1.0-res;
res=Img+res;
imshow("Img",Img);
cv::threshold(res,res,0.85,1,cv::THRESH_BINARY);
cv::resize(res,res,cv::Size(res.cols/2,res.rows/2));
imwrite("result.jpg",res*255);
imshow("Edges",res);
waitKey(0);
return 0;
}
compile
g++ binarize.cpp `pkg-config opencv --cflags --libs`
run
./a.out
error
(Img:27277): Gtk-WARNING **: cannot open display:
update
int main( int argc, char** argv )
{
namedWindow("Img");
namedWindow("Edges");
//Mat Img=imread("D:\\ImagesForTest\\BookPage.JPG",0);
Mat Img=imread("Test2.JPG",0);
Mat res;
Img.convertTo(Img,CV_32FC1,1.0/255.0);
CalcBlockMeanVariance(Img,res);
res=1.0-res;
res=Img+res;
imshow("Img",Img);
cv::threshold(res,res,0.85,1,cv::THRESH_BINARY);
cv::resize(res,res,cv::Size(res.cols/2,res.rows/2));
imwrite("result.tif",res*255);
imshow("Edges",res);
waitKey(0);
return 0;
}
Just built this code on ubuntu 14.03 x64, using the same command line as you used, no any messages, runs fine.
I think warning related to your system environment.
My code is for the purposes of detecting various shapes based off the number of vertices they have. I've finally accomplished that and it works perfectly for simple images like shown here: http://i.imgur.com/f9qvBwF.png However for this thresh image: http://i.imgur.com/jhl0NUQ.png it creates hundreds of shapes because of all the little pixels. Now I know enough of OpenCV to know there's eroding and dilating, but it seems like the best approach would be to exclude contours whose area is below a certain pixel count, however I don't know how to integrate the contourArea() function into my code such that it would work.
Here is my current code:
#include "opencv2/core/core.hpp"
#include "opencv2/flann/miniflann.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/photo/photo.hpp"
#include "opencv2/video/video.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/imgproc/imgproc_c.h"
using namespace cv;
using namespace std;
Mat img;
Mat img_gray;
void contour_finder(int, void*);
int main(int argc, char *argv[])
{
img = imread("C:/Users/wyndr_000/Documents/VisualStudio2013/Projects/OpenCV_Template/OpenCV_Template/testpic.png", CV_LOAD_IMAGE_UNCHANGED);
cvtColor(img, img_gray, CV_RGB2GRAY);
contour_finder(0, 0);
waitKey();
}
void contour_finder(int, void*)
{
Mat img_thresh;
Mat drawn_contours;
threshold(img_gray, img_thresh, 183, 255, 2);
imshow("Thresh Image", img_thresh);
vector<vector<Point> > contours;
vector<Point> result;
findContours(img_thresh, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
// Find a way to filter it out based on Area
for (size_t i = 0; i < contours.size(); i++){
approxPolyDP(Mat(contours[i]), result, arcLength(Mat(contours[i]), true)*0.02, true);
// if (contourArea(result) < 49)
//{
if (result.size() == 3)
{
cout << "TRIANGLE\n";
}
else if (result.size() == 4)
{
cout << "QUADRILATERAL\n";
}
else if (result.size() == 5)
{
cout << "PENTAGON\n";
}
else if (result.size() == 6)
{
cout << "HEXAGON\n";
}
else if (result.size() == 10)
{
cout << "STAR\n";
}
else if (result.size() == 12)
{
cout << "PLUS-SIGN\n";
}
// }
}
/* drawn_contours = Mat::zeros(img_thresh.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(drawn_contours, contours, i, color, 2, 8, hierarchy, 0, Point());
}
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawn_contours); */
}
You'll notice where I declare what different amounts of vertices indicate, I have a commented contourArea function, because that's where I imagined it would go.
I am using OpenCV 2.4.6.
I am trying to get all the convexity defect depth_points of the biggest contour. But i am getting the bellow exception
Assertion failed (mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & fixedDepthMask) != 0)) in unknown function
the current code is pasted bellow
Thank you for any help
vector<vector<Point> >hulls( 1 );
vector<Point> hull;
std::vector<Vec4i> defects;
if(contours.size()>1){
convexHull( Mat(contours[largest_contour_index]), hulls[0], false );
convexityDefects(contours[largest_contour_index], hulls[0], defects);
drawContours(sourceVideo,contours,largest_contour_index,Scalar(255, 0, 0));
drawContours(sourceVideo,hulls,0,Scalar(0, 255, 0));
}
the error is in this line
convexityDefects(contours[largest_contour_index], hulls[0], defects);
Try this it works for me:
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <ctype.h>
#include <time.h>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
String window_name = "Hand_HSV";
Mat frame,copyFrame;
// Detect Skin from YCrCb
Mat DetectYCrCb(Mat img,Scalar min, Scalar max){
Mat skin;
cvtColor(img, skin, cv::COLOR_RGB2YCrCb);
inRange(skin, min, max, skin);
Mat rect_12 = getStructuringElement(cv::MORPH_RECT, Size(12,12) , Point(6,6));
erode(skin, skin, rect_12,Point(),1);
Mat rect_6 = getStructuringElement(cv::MORPH_RECT, Size(6,6) , Point(3,3));
dilate(skin,skin,rect_6,Point(),2);
return skin;
}
void DetectContour(Mat img){
Mat drawing = Mat::zeros( img.size(), CV_8UC3 );
vector<vector<Point> > contours;
vector<vector<Point> > bigContours;
vector<Vec4i> hierarchy;
findContours(img,contours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE, Point());
if(contours.size()>0)
{
vector<vector<int> >hull( contours.size() );
vector<vector<Vec4i>> convDef(contours.size() );
vector<vector<Point>> hull_points(contours.size());
vector<vector<Point>> defect_points(contours.size());
for( int i = 0; i < contours.size(); i++ )
{
if(contourArea(contours[i])>5000)
{
convexHull( contours[i], hull[i], false );
convexityDefects( contours[i],hull[i], convDef[i]);
// start_index, end_index, farthest_pt_index, fixpt_depth
for(int k=0;k<hull[i].size();k++)
{
int ind=hull[i][k];
hull_points[i].push_back(contours[i][ind]);
}
for(int k=0;k<convDef[i].size();k++)
{
if(convDef[i][k][3]>20*256)
{
int ind_0=convDef[i][k][0];
int ind_1=convDef[i][k][1];
int ind_2=convDef[i][k][2];
defect_points[i].push_back(contours[i][ind_2]);
cv::circle(drawing,contours[i][ind_0],5,Scalar(0,255,0),-1);
cv::circle(drawing,contours[i][ind_1],5,Scalar(0,255,0),-1);
cv::circle(drawing,contours[i][ind_2],5,Scalar(0,0,255),-1);
cv::line(drawing,contours[i][ind_2],contours[i][ind_0],Scalar(0,0,255),1);
cv::line(drawing,contours[i][ind_2],contours[i][ind_1],Scalar(0,0,255),1);
}
}
drawContours( drawing, contours, i, Scalar(0,255,0), 1, 8, vector<Vec4i>(), 0, Point() );
drawContours( drawing, hull_points, i, Scalar(255,0,0), 1, 8, vector<Vec4i>(), 0, Point() );
}
}
}
namedWindow( "Hull demo",cv::WINDOW_AUTOSIZE );
imshow( "Hull demo", drawing );
}
int main( int argc, char** argv )
{
VideoCapture capture(0);
//VideoCapture capture("Video_Hand.MPG");
namedWindow( window_name, cv::WINDOW_AUTOSIZE );
if (capture.isOpened()){
while(true)
{
capture >> frame;
imshow( window_name, frame);
Mat skinYCrCb = DetectYCrCb(frame,Scalar(0, 100, 80), Scalar(255, 185, 135));
imshow("Result",skinYCrCb);
DetectContour(skinYCrCb);
int c = waitKey(10);
if( (char)c == 27 )
{
break;
}
}
}
return 0;
}
Are you sure vector<vector<Point> >hulls is correct? The documentation (docs.opencv.org) mentions, for the 2nd parameter of convexityDefects:
convexhull – Convex hull obtained using convexHull() that should contain indices of the contour points that make the hull.
So i think it should be rather vector<vector<int> >hulls