I use below code for object detection.
int main(int argc, char* argv[]){
VideoCapture cap(0);
if (!cap.isOpened()){
cout << "Cannot open the video cam" << endl;
return -1;}
int totalFrameNumber = cap.get(CV_CAP_PROP_FRAME_COUNT);
Mat frame;
namedWindow("MyVideo", CV_WINDOW_AUTOSIZE);
while (1)
{
bool bSuccess = cap.read(frame); // read a new frame from video
if (!bSuccess)
{
cout << "Cannot read a frame from video stream" << endl;
break;
}
Mat frame2;
Rect rectangle2(420,280, 40, 40);
rectangle(frame, rectangle2, Scalar(255, 255, 255));
Mat cornerstrength;
cornerHarris(frame, cornerstrength, 3, 3, 0.1);
//threshold the corner strength
Mat harriscorners;
double th = 0.00001;
threshold(cornerstrength, harriscorners, th, 255, THRESH_BINARY);
morphologyEx(harriscorners, harriscorners, MORPH_CLOSE, Mat(), Point(-1, -1), 6);
//local maxima detection
Mat dilated, localMax;
dilate(cornerstrength, dilated, Mat());
compare(cornerstrength, dilated, localMax, CMP_EQ);
threshold(cornerstrength, harriscorners, th, 255, THRESH_BINARY);
harriscorners.convertTo(harriscorners, CV_8U);
bitwise_and(harriscorners, localMax, harriscorners);
harriscorners.convertTo(harriscorners, CV_32F);
Mat S(0, 2, CV_32SC1);
//drawing a circle around corners
for (int j = 0;j < harriscorners.rows;j++)
for (int i = 0;i < harriscorners.cols;i++)
{
if (harriscorners.at<float>(j, i)> 0)
{ circle(frame, Point(i, j), 5, Scalar(255), 2, 8);
Mat pt(1, 2, CV_32SC1);
pt.at<int>(1, 0) = i;
pt.at<int>(0, 1) = j;
// Add the point to S
S.push_back(pt);
for (int x = 430; x < 460; x++)
for (int y = 285; y < 315; y++)
if ((pt.at<int>(1, 0) = i) == x && (pt.at<int>(0, 1) = j) == y))
{
Rect rectangle2(430, 285, 30,30);}}}
imshow("MyVideo", frame);
if (waitKey(30) == 27)
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
I want When the condition if ((pt.at(1, 0) = i) == x && (pt.at(0, 1) = j) == y)) is established then the size of rectangle2 from
rectangle2(420,280,40,40) Change to rectangle2(430,285,30,30).I can do this change but when I use my code Both rectangle(previous rectangle2 and new rectangle2)are displayed in picture.but I want to display onle new rectangle2.do you have any idea to solve my problem? thanks a lot..
As I said in my comments, you need to create a clone and keep frame almost a constant.
So, in this part:
Rect rectangle2(420,280, 40, 40);
rectangle(frame, rectangle2, Scalar(255, 255, 255));
Mat cornerstrength;
cornerHarris(frame, cornerstrength, 3, 3, 0.1);
Write something more like this
cv::Mat frameCopy = frame.clone();
Rect rectangle2(420,280, 40, 40);
rectangle(frameCopy , rectangle2, Scalar(255, 255, 255));
Mat cornerstrength;
cornerHarris(frameCopy , cornerstrength, 3, 3, 0.1);
Then, in this part, I am not sure what it is intended to do
for (int x = 430; x < 460; x++)
for (int y = 285; y < 315; y++)
if ((pt.at<int>(1, 0) = i) == x && (pt.at<int>(0, 1) = j) == y))
{
Rect rectangle2(430, 285, 30,30);
}
}
}
imshow("MyVideo", frame);
But probably you want to show the new image with a new rectangle, so You can do something like before again:
cv::Mat anotherCopy= frame.clone();
Rect rectangleInLoop(430,280,30,30);
rectangle(anotherCopy, rectangleInLoop, Scalar(255, 255, 255));
imshow("MyVideo", anotherCopy);
Related
I am fairly newbie in OpenCV and C++.
And I am stuck at the problem , which might seem like a fairly trivial.
I am trying to distinguish circle from other shapes, such as rectagular, square, triangle, and etc...
This is the code below what I use
void setLabel(Mat& image, string str, vector<Point> contour){
int fontface = FONT_HERSHEY_SIMPLEX;
double scale = 0.5;
int thickness = 1;
int baseline = 0;
Size text = getTextSize(str, fontface, scale, thickness, &baseline);
Rect r = boundingRect(contour);
Point pt(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2));
rectangle(image, pt + Point(0, baseline), pt + Point(text.width, -text.height), CV_RGB(200, 200, 200), CV_FILLED);
putText(image, str, pt, fontface, scale, CV_RGB(0, 0, 0), thickness, 8);
}
int main(){
Mat img_input, img_result, img_gray;
String filepath("C:\\Users\\PC\\Desktop\\kist\\test.png");
img_input = imread(filepath, IMREAD_COLOR);
if (img_input.empty()){
cout << "Could not open or find the image" << std::endl;
return -1;
}
cvtColor(img_input, img_gray, COLOR_BGR2GRAY);
medianBlur(img_gray, img_gray, 5);
vector <Vec3f> circles;
HoughCircles(img_gray, circles, CV_HOUGH_GRADIENT, 1, 20, 200, 50, 0, 0);
threshold(img_gray, img_gray, 125, 255, THRESH_BINARY_INV | THRESH_OTSU);
vector<vector<Point> > contours;
findContours(img_gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
vector<Point2f> approx;
img_result = img_input.clone();
for (size_t i = 0; i < contours.size(); i++){
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
if (fabs(contourArea(Mat(approx))) > 0){
int size = approx.size();
if (size % 2 == 0) {
line(img_result, approx[0], approx[approx.size() - 1], Scalar(0, 255, 0), 2);
for (int k = 0; k < size - 1; k++)
line(img_result, approx[k], approx[k + 1], Scalar(0, 255, 0), 2);
for (int k = 0; k < size; k++)
circle(img_result, approx[k], 3, Scalar(0, 0, 255));
for (size_t j = 0; j < circles.size(); j++) {
Vec3i c = circles[j];
Point center = Point(c[0], c[1]);
circle(img_result, center, 2, Scalar(0, 255, 0), 2, LINE_AA);
int radius = c[2];
circle(img_result, center, radius, Scalar(0, 255, 0), 2, LINE_AA);
}
}
else if (size % 2 > 0) {
line(img_result, approx[0], approx[approx.size() - 1], Scalar(0, 255, 0), 2);
for (int k = 0; k < size - 1; k++)
line(img_result, approx[k], approx[k + 1], Scalar(0, 255, 0), 2);
for (int k = 0; k < size; k++)
circle(img_result, approx[k], 3, Scalar(0, 0, 255));
}
if (size == 3)
setLabel(img_result, "triangle", contours[i]);
else if (size == 4 && isContourConvex(Mat(approx)))
setLabel(img_result, "rectangle", contours[i]);
else if (size == 5 && isContourConvex(Mat(approx)))
setLabel(img_result, "pentagon", contours[i]);
else if (size == 6 && isContourConvex(Mat(approx)))
setLabel(img_result, "hexagon", contours[i]);
else if (size == 10 && isContourConvex(Mat(approx)))
setLabel(img_result, "decagon", contours[i]);
else {
setLabel(img_result, to_string(approx.size()), contours[i]);
}
}
else if (fabs(contourArea(Mat(approx))) == 0) {
for (size_t i = 0; i < circles.size(); i++) {
Vec3i c = circles[i];
Point center = Point(c[0], c[1]);
circle(img_result, center, 2, Scalar(0, 100, 100), 2, LINE_AA);
int radius = c[2];
circle(img_result, center, radius, Scalar(255, 0, 255), 2, LINE_AA);
}
setLabel(img_result, to_string(approx.size()), contours[i]);
}
}
imshow("input", img_input);
imshow("result", img_result);
And as shown in the figure below, I was able to find out vertex of each figure and draw lines.
However, I want to remove the vertex and straight lines and leave the circle outline from circle shape. And further, I would like to describe the circle shape as 'circle' and count the number of each shape.
Please help me ~~
Thanks a ton !!
enter image description here
So, basically everything is working fine for my program.
This program is just a simple background estimation that extracts foreground with the BackgroundSubtractor class. However, whenever the program terminates, I end up with an exception. I tried debugging it and the error message says, "Information not available, no symbols loaded for opencv_world331d.lib"
What should I do to solve this problem?
Here is the code:
/*This code detects people and draws a bounding box around them*/
/*Uses "background subtraction" in order to keep track of the moving objects in the frames*/
#include "cv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Ptr<BackgroundSubtractor> bg_model = createBackgroundSubtractorMOG2();
VideoCapture cap("people.mp4");
Mat first_frame, frame, main_frame, avg, foregdMask, backgdImg, foregdImg, bg_subtraction, bg_gray;
int cnt = 2;
int cap_width = (int)cap.get(CV_CAP_PROP_FRAME_WIDTH);
int cap_height = (int)cap.get(CV_CAP_PROP_FRAME_HEIGHT);
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));//Size(5,5)
vector<vector<Point>>contours;
vector<Vec4i>hierarchy;
int w_threshold = 40; //contour thresholds
int h_threshold = 60;
int num_con;
int fps = (int)(cap.get(CV_CAP_PROP_FPS));
int delay = 1000 / fps;
int frameNum = 0;
bool stop = false;
int key = 0;
//Store the first frame(since it does not have any moving object present)
cap >> first_frame;
//imshow("FIRST_FRAME", first_frame);
while (1) //For each loop, read single frame
{
if (!stop) {
if (!cap.read(main_frame)) //Reads in the frame
break;
if (main_frame.empty())
{
cout << "Error! No frame received!" << endl;
break;
}
frame = main_frame.clone();//Maintain a copy of the main frame
cvtColor(main_frame, main_frame, CV_BGR2GRAY);
medianBlur(main_frame, main_frame, 7);
//Gaussian Mixture Model (GMM)
if (foregdMask.empty()) //Our foreground mask
foregdMask.create(frame.size(), frame.type());
bg_model->apply(main_frame, foregdMask, true ? -1 : 0); //Compute foreground mask
//GaussianBlur(foregdMask, foregdMask, Size(11, 11), 3.5, 3.5);
GaussianBlur(foregdMask, foregdMask, Size(3, 3), 0.5, 0.5);
threshold(foregdMask, foregdMask, 130, 255, THRESH_BINARY);
foregdImg = Scalar::all(0);
frame.copyTo(foregdImg, foregdMask);
bg_model->getBackgroundImage(backgdImg);
//erode(foregdMask, foregdMask, kernel, Point(-1, -1), 1);
dilate(foregdMask, foregdMask, kernel, Point(-1, -1), 2);
imshow("foreground Mask", foregdMask);
imshow("foreground Image", foregdImg);
imshow("gray frame", main_frame);
//Finding contours(lines)
findContours(foregdMask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
vector<Rect> rect(contours.size());
num_con = 0;
//Drawing rectangles around the contours
for (int i = 0; i < contours.size(); i++)
rect[i] = boundingRect(Mat(contours[i])); //Calculating the up-right bounding rectangle of point sets
for (int i = 0; i < contours.size(); i++) {
if (rect[i].width > w_threshold || rect[i].height > h_threshold)//The size of the contour must be larger than the thresholds
{
rectangle(frame, rect[i], 0, 2, 8, 0); //Draw the boxes on the original frame
num_con++; //Count the number of boxes
}
}
string c = to_string(num_con);
putText(frame, "Number of people:", Point(200, 200), 1, 2, Scalar(0, 200, 0), 3, 8, false);
putText(frame, c, Point(520, 200), 1, 2, Scalar(255, 200, 0), 3, 8, false);
imshow("FRAME", frame);
frameNum++; //Increment the number of frame per loop
key = waitKey(delay);
if (key == 32) //Pause
{
if (stop == false)
{
stop = true;
}
else
stop = false;
}
else if (key == 27) //"ESC" terminates the video
break;
}
else //Resume
{
key = waitKey(delay);
if (key == 32)
stop = false;
}
}
return 0;
}
I am trying to make a hand recognition system but when i used grayscale for cvtColor, i get debug assertion fail but when i use HSV the code works fine. Can you resolve this ? I am a newbie in opencv.
#include "stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/objdetect.hpp"
#include < opencv2\opencv.hpp>
#include < stdio.h>
#include <iostream>
using namespace std;
using namespace cv;
int thresh = 100;
int findBiggestContour(vector<vector<Point> > contours){
int indexOfBiggestContour = -1;
int sizeOfBiggestContour = 0;
for (int i = 0; i < contours.size(); i++){
if (contours[i].size() > sizeOfBiggestContour){
sizeOfBiggestContour = contours[i].size();
indexOfBiggestContour = i;
}
}
return indexOfBiggestContour;
}
void shifcontour(vector<Point>& contour, int x, int y)
{
for (size_t i = 0; i<contour.size(); i++)
{
contour[i].x += x;
contour[i].y += y;
}
}
int main()
{
cout << "beginning";
VideoCapture cap("pathaka.MP4");
if (!cap.isOpened()) // check if we succeeded
return -1;
Ptr<BackgroundSubtractor> pMOG2 = createBackgroundSubtractorMOG2();
for (;;)
{
Mat original, img;
cap >> img;
imshow("Source", img);
Mat hsv;
cvtColor(img, hsv, CV_BGR2GRAY);
Mat bw;
inRange(hsv, Scalar(0, 30, 80), Scalar(20, 150, 255), bw);
GaussianBlur(bw, bw, Size(7, 7), 1.5, 1.5);
Canny(bw, bw, 0, 30, 3);
vector<vector<Point> > contours;
vector<vector<Point> > convex_hull;
vector<Vec4i> hierarchy;
int erosion_type = MORPH_ELLIPSE;
int erosion_size = 0;
Mat element = getStructuringElement(erosion_type,
Size(2 * erosion_size + 1, 2 * erosion_size + 1),
Point(erosion_size, erosion_size));
dilate(bw, bw, element);
findContours(bw, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
int s = findBiggestContour(contours);
Mat drawing = Mat::zeros(img.size(), CV_8UC1);
dilate(drawing, drawing, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
dilate(drawing, drawing, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
std::vector<cv::Point> cnt;
cnt = contours[s];
Moments M;
M = cv::moments(cnt);
cv::Point result;
result = cv::Point(M.m10 / M.m00, M.m01 / M.m00);
Point center(drawing.cols / 2, drawing.rows / 2);
cv::circle(drawing, center, 3, Scalar(255, 255, 255), -1, 8, 0);
int x;
if (result.x > center.x)
{
x = result.x - center.x;
x = -x;
}
else
{
x = result.x - center.x;
}
int y;
if (result.y < center.y)
{
y = center.y - result.y;
}
else
{
y = center.y - result.y;
}
cout << "x:" << x << endl;
cout << "y: " << y << endl;
shifcontour(contours[s], x, y);
drawContours(drawing, contours, s, Scalar(255), -1, 8, hierarchy, 0, Point());
imshow("Hsv", drawing);
if (waitKey(30) >= 0) break;
}
return 0;
}
I think the problem is:
findContours(bw, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
contours now may have something inside, but it could be empty, right? Then, you do this:
int s = findBiggestContour(contours);
If contours.size() == 0, then s == -1, correct?
But after that, you do this:
std::vector<cv::Point> cnt;
cnt = contours[s];
If contours is empty, contours[-1] throws vector subscript out of range.
You should check if (s != -1) before using contours[s], ok?
Perhaps you should process the contours only if there is any, like this:
findContours(bw, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
if (contours.size() > 0) {
int s = findBiggestContour(contours);
Mat drawing = Mat::zeros(img.size(), CV_8UC1);
// these dilates are useless, because drawing is an empty image!
dilate(drawing, drawing, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
dilate(drawing, drawing, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
std::vector<cv::Point> cnt = contours[s];
Moments M = cv::moments(cnt);
Point result = cv::Point(M.m10 / M.m00, M.m01 / M.m00);
Point center(drawing.cols / 2, drawing.rows / 2);
circle(drawing, center, 3, Scalar(255, 255, 255), -1, 8, 0);
int x;
if (result.x > center.x) {
x = result.x - center.x;
x = -x;
} else {
x = result.x - center.x;
}
// is this correct? y has the same value in both cases...
int y;
if (result.y < center.y) y = center.y - result.y;
else y = center.y - result.y;
cout << "x:" << x << endl;
cout << "y: " << y << endl;
shifcontour(contours[s], x, y);
drawContours(drawing, contours, s, Scalar(255), -1, 8, hierarchy, 0, Point());
imshow("Hsv", drawing);
}
I need to binarize images with text.. It works very well but in some cases the output is empty (white image)
code
/*
* Compile
* # g++ txtbin.cpp -o txtbin `pkg-config opencv --cflags --libs`
*
* Run
* # ./txtbin input.jpg output.png
*/
#include "string"
#include "fstream"
#include "/usr/include/opencv2/opencv.hpp"
#include "/usr/include/boost/tuple/tuple.hpp"
using namespace std;
using namespace cv;
using namespace boost;
void CalcBlockMeanVariance(Mat& Img, Mat& Res, float blockSide=21, float contrast=0.01){
/*
* blockSide: set greater for larger fonts in image
* contrast: set smaller for lower contrast 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));
meanStdDev(patch, m, s);
if(s[0] > contrast){
Res.at<float>(i / blockSide, j / blockSide) = m[0];
}
else{
Res.at<float>(i / blockSide, j / blockSide) = 0;
}
}
}
resize(I, smallImg, Res.size());
threshold(Res, inpaintmask, 0.02, 1.0, THRESH_BINARY);
Mat inpainted;
smallImg.convertTo(smallImg, CV_8UC1, 255);
inpaintmask.convertTo(inpaintmask, CV_8UC1);
inpaint(smallImg, inpaintmask, inpainted, 5, INPAINT_TELEA);
resize(inpainted, Res, Img.size());
Res.convertTo(Res, CV_32FC1, 1.0 / 255.0);
}
tuple<int, int, int, int> detect_text_box(string input, Mat& res, bool draw_contours=false){
Mat large = imread(input);
bool test_output = false;
int
top = large.rows,
bottom = 0,
left = large.cols,
right = 0;
int
rect_bottom,
rect_right;
Mat rgb;
// downsample and use it for processing
pyrDown(large, rgb);
Mat small;
cvtColor(rgb, small, CV_BGR2GRAY);
// morphological gradient
Mat grad;
Mat morphKernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
morphologyEx(small, grad, MORPH_GRADIENT, morphKernel);
// binarize
Mat bw;
threshold(grad, bw, 0.0, 255.0, THRESH_BINARY | THRESH_OTSU);
// connect horizontally oriented regions
Mat connected;
morphKernel = getStructuringElement(MORPH_RECT, Size(9, 1));
morphologyEx(bw, connected, MORPH_CLOSE, morphKernel);
// find contours
Mat mask = Mat::zeros(bw.size(), CV_8UC1);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(connected, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
// filter contours
for(int idx = 0; idx >= 0; idx = hierarchy[idx][0]){
Rect rect = boundingRect(contours[idx]);
Mat maskROI(mask, rect);
maskROI = Scalar(0, 0, 0);
// fill the contour
drawContours(mask, contours, idx, Scalar(255, 255, 255), CV_FILLED);
// ratio of non-zero pixels in the filled region
double r = (double)countNonZero(maskROI) / (rect.width * rect.height);
// assume at least 45% of the area is filled if it contains text
if (r > 0.45 &&
(rect.height > 8 && rect.width > 8) // constraints on region size
// these two conditions alone are not very robust. better to use something
//like the number of significant peaks in a horizontal projection as a third condition
){
if(draw_contours){
rectangle(res, Rect(rect.x * 2, rect.y * 2, rect.width * 2, rect.height * 2), Scalar(0, 255, 0), 2);
}
if(test_output){
rectangle(rgb, rect, Scalar(0, 255, 0), 2);
}
if(rect.y < top){
top = rect.y;
}
rect_bottom = rect.y + rect.height;
if(rect_bottom > bottom){
bottom = rect_bottom;
}
if(rect.x < left){
left = rect.x;
}
rect_right = rect.x + rect.width;
if(rect_right > right){
right = rect_right;
}
}
}
if(draw_contours){
rectangle(res, Point(left * 2, top * 2), Point(right * 2, bottom * 2), Scalar(0, 0, 255), 2);
}
if(test_output){
rectangle(rgb, Point(left, top), Point(right, bottom), Scalar(0, 0, 255), 2);
imwrite(string("test_text_contours.jpg"), rgb);
}
return make_tuple(left * 2, top * 2, (right - left) * 2, (bottom - top) * 2);
}
int main(int argc, char* argv[]){
string input;
string output = "output.png";
int
width = 0,
height = 0;
bool
crop = false,
draw = false;
float margin = 0;
// Return error if arguments are missing
if(argc < 3){
cerr << "\nUsage: txtbin input [options] output\n\n"
"Options:\n"
"\t-w <number> -- set max width (keeps aspect ratio)\n"
"\t-h <number> -- set max height (keeps aspect ratio)\n"
"\t-c -- crop text content contour\n"
"\t-m <number> -- add margins (number in %)\n"
"\t-d -- draw text content contours (debugging)\n" << endl;
return 1;
}
// Parse arguments
for(int i = 1; i < argc; i++){
if(i == 1){
input = string(argv[i]);
// Return error if input file is invalid
ifstream stream(input.c_str());
if(!stream.good()){
cerr << "Error: Input file is invalid!" << endl;
return 1;
}
}
else if(string(argv[i]) == "-w"){
width = atoi(argv[++i]);
}
else if(string(argv[i]) == "-h"){
height = atoi(argv[++i]);
}
else if(string(argv[i]) == "-c"){
crop = true;
}
else if(string(argv[i]) == "-m"){
margin = atoi(argv[++i]);
}
else if(string(argv[i]) == "-d"){
draw = true;
}
else if(i == argc - 1){
output = string(argv[i]);
}
}
Mat Img = imread(input, CV_LOAD_IMAGE_GRAYSCALE);
Mat res;
Img.convertTo(Img, CV_32FC1, 1.0 / 255.0);
CalcBlockMeanVariance(Img, res);
res = 1.0 - res;
res = Img + res;
threshold(res, res, 0.85, 1, THRESH_BINARY);
int
txt_x,
txt_y,
txt_width,
txt_height;
if(crop || draw){
tie(txt_x, txt_y, txt_width, txt_height) = detect_text_box(input, res, draw);
}
if(crop){
//res = res(Rect(txt_x, txt_y, txt_width, txt_height)).clone();
res = res(Rect(txt_x, txt_y, txt_width, txt_height));
}
if(margin){
int border = res.cols * margin / 100;
copyMakeBorder(res, res, border, border, border, border, BORDER_CONSTANT, Scalar(255, 255, 255));
}
float
width_input = res.cols,
height_input = res.rows;
bool resized = false;
// Downscale image
if(width > 0 && width_input > width){
float scale = width_input / width;
width_input /= scale;
height_input /= scale;
resized = true;
}
if(height > 0 && height_input > height){
float scale = height_input / height;
width_input /= scale;
height_input /= scale;
resized = true;
}
if(resized){
resize(res, res, Size(round(width_input), round(height_input)));
}
imwrite(output, res * 255);
return 0;
}
Ok :)
Set blockSide smaller (7 for instance) it will give you result image as shown below. It depends on font size, smaller fonts need smaller block size, else text will be filtered out and you get empty image.
#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=9) // 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;
}
I'm having Heap corruption exception while compiling this code which I found on the internet. I'm a beginner and I don't know how to solve the problem.
the exception occurred in the following line:
matcher.knnMatch(desObject, des_image, matches, 2);
Could someone tell me what should I replace this line of code with?
The complete source code:
cv::initModule_nonfree();
// turn performance analysis functions on if testing = true
bool testing = false;
double t; // timing variable
// load training image
Mat object = imread("boo2.png", CV_LOAD_IMAGE_GRAYSCALE);
if (!object.data) {
cout << "Can't open image";
return -1;
}
namedWindow("Good Matches", CV_WINDOW_AUTOSIZE);
// SURF Detector, and descriptor parameters
int minHess = 3000;
vector<KeyPoint> kpObject, kpImage;
Mat desObject, desImage;
// Performance measures calculations for report
if (testing) {
cout << object.rows << " " << object.cols << endl;
// calculate integral image
Mat iObject;
integral(object, iObject);
imshow("Good Matches", iObject);
imwrite("boo2.png", iObject);
cvWaitKey(0);
// calculate number of interest points, computation time as f(minHess)
int minHessVector[] = {100, 500, 1000, 1500, 2000, 2500, 3000,
3500, 4000, 4500, 5000, 5500, 6000, 6500,
7000, 7500, 8000, 8500, 9000, 9500, 10000};
int minH;
std::ofstream file;
file.open("C:/School/Image Processing/TimingC.csv", std::ofstream::out);
for (int i = 0; i < 20; i++) {
minH = minHessVector[i];
t = (double)getTickCount();
SurfFeatureDetector detector(minH);
detector.detect(object, kpObject);
t = ((double)getTickCount() - t) / getTickFrequency();
file << minHess << "," << kpObject.size() << "," << t << ",";
cout << t << " " << kpObject.size() << " " << desObject.size() << endl;
t = (double)getTickCount();
SurfDescriptorExtractor extractor;
extractor.compute(object, kpObject, desObject);
t = ((double)getTickCount() - t) / getTickFrequency();
file << t << endl;
}
file.close();
// Display keypoints on training image
Mat interestPointObject = object;
for (unsigned int i = 0; i < kpObject.size(); i++) {
if (kpObject[i].octave) {
circle(interestPointObject, kpObject[i].pt, kpObject[i].size, 0);
string octaveS;
switch (kpObject[i].octave) {
case 0:
octaveS = "0";
break;
case 1:
octaveS = '1';
break;
case 2:
octaveS = '2';
break;
default:
break;
}
putText(interestPointObject, octaveS, kpObject[i].pt,
FONT_HERSHEY_COMPLEX_SMALL, 1, cvScalar(0, 0, 250), 1, CV_AA);
}
}
imshow("Good Matches", interestPointObject);
imwrite("C:/School/Image Processing/bookIP2.jpg", interestPointObject);
cvWaitKey(0);
}
// SURF Detector, and descriptor parameters, match object
// initialization
minHess = 2000;
SurfFeatureDetector detector(minHess);
detector.detect(object, kpObject);
SurfDescriptorExtractor extractor;
extractor.compute(object, kpObject, desObject);
FlannBasedMatcher matcher;
// Initialize video and display window
VideoCapture cap(1); // camera 1 is webcam
if (!cap.isOpened()) return -1;
// Object corner points for plotting box
vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0, 0);
obj_corners[1] = cvPoint(object.cols, 0);
obj_corners[2] = cvPoint(object.cols, object.rows);
obj_corners[3] = cvPoint(0, object.rows);
// video loop
char escapeKey = 'k';
double frameCount = 0;
float thresholdMatchingNN = 0.7;
unsigned int thresholdGoodMatches = 4;
unsigned int thresholdGoodMatchesV[] = {4, 5, 6, 7, 8, 9, 10};
for (int j = 0; j < 7; j++) {
thresholdGoodMatches = thresholdGoodMatchesV[j];
// thresholdGoodMatches=8;
cout << thresholdGoodMatches << endl;
if (true) {
t = (double)getTickCount();
}
while (escapeKey != 'q') {
frameCount++;
Mat frame;
Mat image;
cap >> frame;
cvtColor(frame, image, CV_RGB2GRAY);
Mat des_image, img_matches, H;
vector<KeyPoint> kp_image;
vector<vector<DMatch>> matches;
vector<DMatch> good_matches;
vector<Point2f> obj;
vector<Point2f> scene;
vector<Point2f> scene_corners(4);
detector.detect(image, kp_image);
extractor.compute(image, kp_image, des_image);
matcher.knnMatch(desObject, des_image, matches, 2);
for (int i = 0; i < min(des_image.rows - 1, (int)matches.size()); i++)
// THIS LOOP IS SENSITIVE TO SEGFAULTS
{
if ((matches[i][0].distance <
thresholdMatchingNN * (matches[i][1].distance)) &&
((int)matches[i].size() <= 2 && (int)matches[i].size() > 0)) {
good_matches.push_back(matches[i][0]);
}
}
// if (good_matches.size()<1)
// good_matches.resize(0,cv::DMatch);
// Draw only "good" matches
drawMatches(object, kpObject, image, kp_image, good_matches, img_matches,
Scalar::all(-1), Scalar::all(-1), vector<char>(),
DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
if (good_matches.size() >= thresholdGoodMatches) {
// Display that the object is found
putText(img_matches, "Object Found", cvPoint(10, 50),
FONT_HERSHEY_COMPLEX_SMALL, 2, cvScalar(0, 0, 250), 1, CV_AA);
for (unsigned int i = 0; i < good_matches.size(); i++) {
// Get the keypoints from the good matches
obj.push_back(kpObject[good_matches[i].queryIdx].pt);
scene.push_back(kp_image[good_matches[i].trainIdx].pt);
}
H = findHomography(obj, scene, CV_RANSAC);
perspectiveTransform(obj_corners, scene_corners, H);
// Draw lines between the corners (the mapped object in the scene
// image )
line(img_matches, scene_corners[0] + Point2f(object.cols, 0),
scene_corners[1] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[1] + Point2f(object.cols, 0),
scene_corners[2] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[2] + Point2f(object.cols, 0),
scene_corners[3] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
line(img_matches, scene_corners[3] + Point2f(object.cols, 0),
scene_corners[0] + Point2f(object.cols, 0), Scalar(0, 255, 0), 4);
} else {
putText(img_matches, "", cvPoint(10, 50), FONT_HERSHEY_COMPLEX_SMALL, 3,
cvScalar(0, 0, 250), 1, CV_AA);
}
// Show detected matches
imshow("Good Matches", img_matches);
escapeKey = cvWaitKey(10);
// imwrite("C:/School/Image Processing/bookIP3.jpg", img_matches);
if (frameCount > 10) escapeKey = 'q';
}
// average frames per second
if (true) {
t = ((double)getTickCount() - t) / getTickFrequency();
cout << t << " " << frameCount / t << endl;
cvWaitKey(0);
}
frameCount = 0;
escapeKey = 'a';
}
// Release camera and exit
cap.release();