I am trying to make the follwing Code by Mohammad Reza Mostajabi (http://alum.sharif.ir/~mostajabi/Tutorial.html) run under Ubuntu 12.04 with OpenCV 2.4.6.1. I made some minor changes with the libraries included and added "cv::initModule_nonfree()" right after starting the main file.
#include "cv.h"
#include "highgui.h"
#include "ml.h"
#include <stdio.h>
#include <iostream>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <vector>
using namespace cv;
using namespace std;
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
char ch[30];
//--------Using SURF as feature extractor and FlannBased for assigning a new point to the nearest one in the dictionary
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
Ptr<DescriptorExtractor> extractor = new SurfDescriptorExtractor();
SurfFeatureDetector detector(500);
//---dictionary size=number of cluster's centroids
int dictionarySize = 1500;
TermCriteria tc(CV_TERMCRIT_ITER, 10, 0.001);
int retries = 1;
int flags = KMEANS_PP_CENTERS;
BOWKMeansTrainer bowTrainer(dictionarySize, tc, retries, flags);
BOWImgDescriptorExtractor bowDE(extractor, matcher);
void collectclasscentroids() {
IplImage *img;
int i,j;
for(j=1;j<=4;j++)
for(i=1;i<=60;i++){
sprintf( ch,"%s%d%s%d%s","train/",j," (",i,").jpg");
const char* imageName = ch;
img = cvLoadImage(imageName,0);
vector<KeyPoint> keypoint;
detector.detect(img, keypoint);
Mat features;
extractor->compute(img, keypoint, features);
bowTrainer.add(features);
}
return;
}
int main(int argc, char* argv[])
{
cv::initModule_nonfree();
int i,j;
IplImage *img2;
cout<<"Vector quantization..."<<endl;
collectclasscentroids();
vector<Mat> descriptors = bowTrainer.getDescriptors();
int count=0;
for(vector<Mat>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
count+=iter->rows;
}
cout<<"Clustering "<<count<<" features"<<endl;
//choosing cluster's centroids as dictionary's words
Mat dictionary = bowTrainer.cluster();
bowDE.setVocabulary(dictionary);
cout<<"extracting histograms in the form of BOW for each image "<<endl;
Mat labels(0, 1, CV_32FC1);
Mat trainingData(0, dictionarySize, CV_32FC1);
int k=0;
vector<KeyPoint> keypoint1;
Mat bowDescriptor1;
//extracting histogram in the form of bow for each image
for(j=1;j<=4;j++)
for(i=1;i<=60;i++){
sprintf( ch,"%s%d%s%d%s","train/",j," (",i,").jpg");
const char* imageName = ch;
img2 = cvLoadImage(imageName,0);
detector.detect(img2, keypoint1);
bowDE.compute(img2, keypoint1, bowDescriptor1);
trainingData.push_back(bowDescriptor1);
labels.push_back((float) j);
}
//Setting up SVM parameters
CvSVMParams params;
params.kernel_type=CvSVM::RBF;
params.svm_type=CvSVM::C_SVC;
params.gamma=0.50625000000000009;
params.C=312.50000000000000;
params.term_crit=cvTermCriteria(CV_TERMCRIT_ITER,100,0.000001);
CvSVM svm;
printf("%s\n","Training SVM classifier");
bool res=svm.train(trainingData,labels,cv::Mat(),cv::Mat(),params);
cout<<"Processing evaluation data..."<<endl;
Mat groundTruth(0, 1, CV_32FC1);
Mat evalData(0, dictionarySize, CV_32FC1);
k=0;
vector<KeyPoint> keypoint2;
Mat bowDescriptor2;
Mat results(0, 1, CV_32FC1);;
for(j=1;j<=4;j++)
for(i=1;i<=60;i++){
sprintf( ch,"%s%d%s%d%s","eval/",j," (",i,").jpg");
const char* imageName = ch;
img2 = cvLoadImage(imageName,0);
detector.detect(img2, keypoint2);
bowDE.compute(img2, keypoint2, bowDescriptor2);
evalData.push_back(bowDescriptor2);
groundTruth.push_back((float) j);
float response = svm.predict(bowDescriptor2);
results.push_back(response);
}
//calculate the number of unmatched classes
double errorRate = (double) countNonZero(groundTruth- results) / evalData.rows;
printf("%s%f","Error rate is ",errorRate);
return 0;
}
After doing this I can compile the Code without problems. I can also run it within Eclipse, but once I try to make it work in terminal I get the following error message:
" OpenCV Error: Assertion failed (!_descriptors.empty()) in add, file /home/mark/Downloads/FP/opencv-2.4.6.1/modules/features2d/src/bagofwords.cpp, line 57
terminate called after throwing an instance of 'cv::Exception'
what(): /home/mark/Downloads/FP/opencv-2.4.6.1/modules/features2d/src/bagofwords.cpp:57: error: (-215) !_descriptors.empty() in function add "
I've been trying to solve the problem for a few days now, but I just cannot get rid of this error. I also tried to do it with CodeBlocks, which gives me the same error. I would appreciate some help very much!
Thanks!
It's possible that your program fails to load input images (when launched from the terminal window) because it can't find them. Make sure that your input images are copied to the directory from which you run the application. Eclipse may have a different home directory and hence it sees the image when the program is started in Eclipse.
Related
I am trying the compile the following code to compute the chamfer distance. However I get the following error while compiling it. I am using opencv-3.2 on ubuntu 18.04, 64 bit.
fatal error: opencv2/contrib/contrib.hpp: No such file or directory
Synaptic package manager says that libopencv-contrib-dev and libopencv-contrib-3.2 are installed at /usr/include/opencv2 and /usr/lib/x86_64-linux-gnu respectively. I checked for contrib.hpp but found no file or folder named contrib in these locations.
The code for the chamfer distance computation is as below:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, const char** argv )
{
Mat img = imread(argv[1], 0);
Mat tpl = imread(argv[2], 0);
Mat cimg;
cvtColor(img, cimg, CV_GRAY2BGR);
vector<vector<Point> > results;
vector<float> costs;
int best = chamerMatching( img, tpl, results, costs );
return 0;
}
My question is: How to add the correct headers and get the above chamfer distance code working in opencv 3.2?
It looks like the contrib module is not available in OpenCV 3.2. This module was removed in OpenCV 4.0 and is no longer part of the library. If you want to use the Chamfer matching algorithm in your code, you can try using the matchShapes function from the imgproc module instead. This function can be used to compare the shapes of two contours and return a measure of their similarity:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, const char** argv )
{
Mat img = imread(argv[1], 0);
Mat tpl = imread(argv[2], 0);
// Find the contours of the images
vector<vector<Point> > img_contours;
vector<vector<Point> > tpl_contours;
findContours(img, img_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
findContours(tpl, tpl_contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);
// Compute the Chamfer distance between the contours
double chamfer = matchShapes(img_contours[0], tpl_contours[0], CHAMFER_DIST_L2, 0);
cout << "Chamfer distance: " << chamfer << endl;
return 0;
}
I am trying to load an image, calculate the image pyramid (save every image) and then blur every single image of the pyramid with opencv 3.2 in C++. When I run my program I receive the error:
vector Line:1740 Expression: vector subscript out of range
Here is my code:
#include "stdafx.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <opencv2/shape/shape.hpp>
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
int main(int argc, char** argv)
{
// Read the image
Mat img_1;
img_1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
// Build an image pyramid and save it in a vector of Mat
vector<Mat> img_1_pyramid;
int pyramid_octaves = 3;
buildPyramid(img_1, img_1_pyramid, pyramid_octaves);
/* void cv::buildPyramid (InputArray src, OutputArrayOfArrays dst, int
maxlevel, int borderType = BORDER_DEFAULT) */
// Initialize parameters for the first image pyramid
vector<Mat> reduced_noise_1;
blur(img_1_pyramid[0], reduced_noise_1[0], Size(3,3));
/* void cv::blur (InputArray src, OutputArray dst, Size ksize, Point
anchor=Point(-1,-1), int borderType=BORDER_DEFAULT)*/
return 0;
}
I also tried it with a Mat object: Mat reduced_noise_1; or a vector of predefined size vector<Mat> reduced_noise(4);and I can draw img_1_pyramid[0] with imshow and receive the right image...
When I debug the program I receive an error in Line 621 of cvstd.hpp:
String::String(const char* s)
: cstr_(0), len_(0)
{
if (!s) return;
size_t len = strlen(s); // Here appears the error (only in German;))
memcpy(allocate(len), s, len);
}
I am trying to set up a bag of visual words using openCV 3.0. I have looked a bit everywhere and all I seem to be able to find is code that is only compatible with versions in the 2.x domain. As of now this is what I have:
#include <opencv2/core/core.hpp>
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main(int argc, const char** argv) {
Ptr<FeatureDetector> features;
Ptr<DescriptorExtractor> descriptors;
Ptr<DescriptorMatcher> matcher;
int MAX_ITER = 100;
int EPS = 2;
TermCriteria tc(MAX_ITER + EPS,1,0.001);
int dictSize = 1000;
int retries = 1;
int flags = KMEANS_PP_CENTERS;
BOWKMeansTrainer bowTrainer(dictSize,tc,retries,flags);
BOWImgDescriptorExtractor bowDE(descriptors,matcher);
Mat img1 = imread("/Users/Lucas/Desktop/pic2.jpg");
Mat img2 = imread("/Users/Lucas/Desktop/2.jpg");
vector<KeyPoint> keypoints,keypoints2;
features->detect(img1, keypoints);
features->detect(img2, keypoints2);
Mat myFeatures;
Mat myFeatures2;
descriptors->compute(img1, keypoints, myFeatures);
descriptors->compute(img2, keypoints2, myFeatures2);
bowTrainer.add(myFeatures);
bowTrainer.add(myFeatures2);
Mat dictionary = bowTrainer.cluster();
bowDE.setVocabulary(dictionary);
cout << dictionary << endl;
return 0;
}
I have put this together by using a few tutorials and snippets, but I am running into an issue. When the program gets to
features->detect(img1, keypoints);
it exits with a segmentation fault 11, whatever that means. Could someone help me and point out what it is I am doing wrong?
you have to create your FeatureDetector, DescriptorExtractor first. atm, you got null-pointer instances (that's your segfault).
#include <opencv2/xfeatures2d.hpp>
...
Ptr<FeatureDetector> features = xfeatures2d::SIFT::create();
Ptr<DescriptorExtractor> descriptors = xfeatures2d::SIFT::create();
Ptr<DescriptorMatcher> matcher = makePtr<BFMatcher>(NORM_L2);
note, that since you have to use SIFT or SURF, you will need the opencv_contrib repo installed for this
I tried to extract SIFT key points. It is working fine for a sample image I downloaded (height 400px width 247px horizontal and vertical resolutions 300dpi). Below image shows the extracted points.
Then I tried to apply the same code to a image that was taken and edited by me (height 443px width 541px horizontal and vertical resolutions 72dpi).
To create the above image I rotated the original image then removed its background and resized it using Photoshop, but my code, for that image doesn't extract features like in the first image.
See the result :
It just extract very few points. I expect a result as in the first case.
For the second case when I'm using the original image without any edit the program gives points as the first case.
Here is the simple code I have used
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv2\nonfree\nonfree.hpp>
using namespace cv;
int main(){
Mat src, descriptors,dest;
vector<KeyPoint> keypoints;
src = imread(". . .");
cvtColor(src, src, CV_BGR2GRAY);
SIFT sift;
sift(src, src, keypoints, descriptors, false);
drawKeypoints(src, keypoints, dest);
imshow("Sift", dest);
cvWaitKey(0);
return 0;
}
What I'm doing wrong here? what do I need to do to get a result like in the first case to my own image after resizing ?
Thank you!
Try set nfeatures parameter (may be other parameters also need adjustment) in SIFT constructor.
Here is constructor definition from reference:
SIFT::SIFT(int nfeatures=0, int nOctaveLayers=3, double contrastThreshold=0.04, double edgeThreshold=10, double sigma=1.6)
Your code will be:
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv2\nonfree\nonfree.hpp>
using namespace cv;
using namespace std;
int main(){
Mat src, descriptors,dest;
vector<KeyPoint> keypoints;
src = imread("D:\\ImagesForTest\\leaf.jpg");
cvtColor(src, src, CV_BGR2GRAY);
SIFT sift(2000,3,0.004);
sift(src, src, keypoints, descriptors, false);
drawKeypoints(src, keypoints, dest);
imshow("Sift", dest);
cvWaitKey(0);
return 0;
}
The result:
Dense sampling example:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include "opencv2/nonfree/nonfree.hpp"
int main(int argc, char* argv[])
{
cv::initModule_nonfree();
cv::namedWindow("result");
cv::Mat bgr_img = cv::imread("D:\\ImagesForTest\\lena.jpg");
if (bgr_img.empty())
{
exit(EXIT_FAILURE);
}
cv::Mat gray_img;
cv::cvtColor(bgr_img, gray_img, cv::COLOR_BGR2GRAY);
cv::normalize(gray_img, gray_img, 0, 255, cv::NORM_MINMAX);
cv::DenseFeatureDetector detector(12.0f, 1, 0.1f, 10);
std::vector<cv::KeyPoint> keypoints;
detector.detect(gray_img, keypoints);
std::vector<cv::KeyPoint>::iterator itk;
for (itk = keypoints.begin(); itk != keypoints.end(); ++itk)
{
std::cout << itk->pt << std::endl;
cv::circle(bgr_img, itk->pt, itk->size, cv::Scalar(0,255,255), 1, CV_AA);
cv::circle(bgr_img, itk->pt, 1, cv::Scalar(0,255,0), -1);
}
cv::Ptr<cv::DescriptorExtractor> descriptorExtractor = cv::DescriptorExtractor::create("SURF");
cv::Mat descriptors;
descriptorExtractor->compute( gray_img, keypoints, descriptors);
// SIFT returns large negative values when it goes off the edge of the image.
descriptors.setTo(0, descriptors<0);
imshow("result",bgr_img);
cv::waitKey();
return 0;
}
The result:
I am running the following code to calculated the Running Average of a collection of images read from a video on OpenCV.
EDIT: (Code updated)
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include "opencv2/core/core.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/video/video.hpp"
using namespace std;
using namespace cv;
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Quitting. Insufficient parameters\n");
return 0;
}
char c;
int frameNum = -1;
const char* WIN_MAIN = "Main Window";
namedWindow(WIN_MAIN, CV_WINDOW_AUTOSIZE);
VideoCapture capture;
capture.open(argv[1]);
Mat acc, img;
capture.retrieve(img, 3);
acc = Mat::zeros(img.size(), CV_32FC3);
for(;;) {
if(!capture.grab()) {
printf("End of frame\n");
break;
}
capture.retrieve(img, 3);
Mat floating;
img.convertTo(floating, CV_32FC3);
accumulateWeighted(floating, acc, 0.01);
imshow(WIN_MAIN, img);
waitKey(10);
}
return 0;
}
On running the code with a sample video the following error pops up
OpenCV Error: Assertion failed (dst.size == src.size && dst.channels() == cn) in accumulateWeighted, file /usr/lib/opencv/modules/imgproc/src/accum.cpp, line 430
terminate called after throwing an instance of 'cv::Exception'
what(): /usr/lib/opencv/modules/imgproc/src/accum.cpp:430: error: (-215) dst.size == src.size && dst.channels() == cn in function accumulateWeighted
Aborted (core dumped)
What could be the possible reason for the error? Could you please guide me in the right direction?
Compiler used : g++
OpenCV version : 2.4.5
Thanks!
from the refman:
src – Input image as 1- or 3-channel, 8-bit or 32-bit floating point.
dst – Accumulator image with the same number of channels as input image, 32-bit or 64-bit
floating-point.
so, your camera input img CV_8UC3, and your acc img is (currently) CV_32F. that's a misfit.
you want 3channel floating point for acc, so that's :
acc = Mat::zeros(img.size(), CV_8UC3);`
for more precision, you want to change your img to float type, too, so it would be:
acc = Mat::zeros(img.size(), CV_32FC3); // note: 3channel now
for (;;) {
if(!capture.grab()) {
printf("End of frame\n");
break;
}
capture.retrieve(img); // video probably has 1 stream only
Mat floatimg;
img.convertTo(floatimg, CV_32FC3);
accumulateWeighted(floatimg, acc, 0.01);
EDIT:
try to replace your grab/retrieve sequence by:
for(;;) {
capture >> img;
if ( img.empty() )
break;
As I can read in the OpenCV documentation of retrieve
C++: bool VideoCapture::retrieve(Mat& image, int channel=0);
second argument is the channel
and in the documentation of accumulateWeighted it says :
C++: void accumulateWeighted(InputArray src, InputOutputArray dst,
double alpha, InputArray mask=noArray() )
Parameters:src – Input image as 1- or 3-channel, 8-bit or 32-bit
floating point.
But in your code :
capture.retrieve(img, 2);
I guess you have the wrong channel parameter
I had the same problem problem and here's my solution.
Mat frame, acc;
// little hack, read the first frame
capture >> frame;
acc = Mat::zeros(frame.size(), CV_32FC3);
for(;;) {
...