I am trying to create a Bag of visual Words program, but I am running into an issue. Every time I run the program, I either get a segmentation fault: 11 error, or if I change the dictSize variable I get a error: (-215) N >= K in function kmeans. I have tried resizing the images, using different ones but nothing seems to help. Here is what I have up to now:
#include <opencv2/core/core.hpp>
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
using namespace std;
using namespace cv;
int main(int argc, const char** argv) {
//=================================== LEARN ===================================
struct dirent *de = NULL;
DIR *d = NULL;
d = opendir(argv[1]);
if(d == NULL)
{
perror("Couldn't open directory");
return(2);
}
Mat input;
vector<KeyPoint> keypoints;
Mat descriptor;
Mat featuresUnclustered;
Ptr<DescriptorExtractor> detector = xfeatures2d::SIFT::create();
while((de = readdir(d))){
if ((strcmp(de->d_name,".") != 0) && (strcmp(de->d_name,"..") != 0) && (strcmp(de->d_name,".DS_Store") != 0)) {
char fullPath[] = "./";
strcat(fullPath, argv[1]);
strcat(fullPath, de->d_name);
printf("Current File: %s\n",fullPath);
input = imread(fullPath,CV_LOAD_IMAGE_GRAYSCALE);
cout << "Img size => x: " << input.size().width << ", y: " << input.size().height << endl;
// If the incoming frame is too big, resize it
if (input.size().width > 3000) {
double ratio = (3000.0)/(double)input.size().width;
resize(input, input, cvSize(0, 0), ratio, ratio);
cout << "New size => x: " << input.size().width << ", y: " << input.size().height << endl;
}
detector->detect(input, keypoints);
detector->compute(input, keypoints, descriptor);
featuresUnclustered.push_back(descriptor);
}
}
closedir(d);
int dictSize = 200;
TermCriteria tc(CV_TERMCRIT_ITER,100,0.001);
int retries = 1;
int flags = KMEANS_PP_CENTERS;
BOWKMeansTrainer bowTrainer(dictSize,tc,retries,flags);
Mat dictionary = bowTrainer.cluster(featuresUnclustered);
FileStorage fs("dict.yml",FileStorage::WRITE);
fs << "vocabulary" << dictionary;
fs.release();
return 0;
}
char fullPath[] = "./";
strcat(fullPath, argv[1]);
strcat(fullPath, de->d_name);
That part of your code is a serious bug (undefined behavior, but seg fault most likely).
strcat does not allocate any extra space for the concatenation. It only overwrites whatever follows the terminating null in the first string.
Your fullPath is allocated with just enough space for the initial 2 characters plus terminating null. Whatever follows that terminating null may be memory belonging to some other part of your program.
If you know the maximum file path length for your OS, you can use the crude correction of putting that max plus 2 as a number (or named constant) between the [] in the declaration of fullPath.
The less crude correction is to compute the required lenth of the string you want to build and malloc that much space (be sure to count the terminating null) and combine the three strings there.
Related
I have an input file like this:
Virtual (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A) (A)
The electronic state is 1-A.
Alpha occ. eigenvalues -- -0.26426 -0.26166 -0.25915 -0.25885
Alpha occ. eigenvalues -- -0.25284 -0.25172 -0.24273 -0.23559
Alpha occ. eigenvalues -- -0.20078 -0.19615 -0.17676 -0.10810
Alpha virt. eigenvalues -- -0.07062 -0.06520 -0.05969 -0.01767
Alpha virt. eigenvalues -- -0.01604 -0.00951 -0.00428 0.00041
I would like to export the first line obtaining first 11 characters " Alpha virt.". How should I do? I code by C++ language as below code, but it cant finish while loop functio. I dont know why, I am a fresher. Please help me. Thank you so much.
My C++ code:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#define FILENAME "filelog.txt"
using namespace std;
int main(void) {
char* line_buf = NULL;
size_t line_buf_size = 0;
int line_count = 0;
string s;
std::string dongsosanh = " Alpha virt.";
FILE* fp = fopen(FILENAME, "r");
getline(&line_buf, &line_buf_size, fp);
std::string STRR(line_buf, 11);
do {
line_count++;
getline(&line_buf, &line_buf_size, fp);
} while(STRR.compare(dongsosanh) != 0);
std::cout << STRR << endl;
return 0;
}
Thank you so much.
Many problems with your program:
line_buf - does not have memory allocated, undef behaviour
line_count - is 0, nothing will be red
You are not closing file at the end.
" Alpha virt." - this line will never be found, it has space at the begining.
STRR is never updated after line has been red, endless loop
Working solution:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>
#define FILENAME "filelog.txt"
using namespace std;
int main(void) {
const std::string dongsosanh = "Alpha virt.";
char* line_buf = new char[100];
size_t line_buf_size = 100;
int line_count = 0;
string s;
FILE* fp = fopen(FILENAME, "r");
do {
line_count++;
getline(&line_buf, &line_buf_size, fp);
std::cout << line_buf;
} while(dongsosanh.compare(0, 11, line_buf, 11));
free(line_buf);
fclose(fp);
return 0;
}
This is to show how it works in your case, but you should use vector instead of char* line_buf.
You could just do this:
std::ifstream input(FILENAME);
std::string line;
while(std::getline(input, line)) {
if(line.substr(0, 11) == "Alpha virt.") {
std::cout << line << endl;
return 0;
}
}
EDIT: added the return statement to make sure only the first line starting with 'Alpha virt.' is printed.
I want to resize an RGB image with the Bicubic interpolation. I used the following code :
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <ctime>
#include <iostream>
using namespace std;
//#include <opencv.hpp>
#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv/highgui.h>
using namespace cv;
int main()
{
string fileName = "myImage.jpg";
Mat imageSrc = cv::imread(fileName, CV_LOAD_IMAGE_UNCHANGED); // Read the file
if (!imageSrc.data) // Check for invalid input
{
cout << "Could not open or find the image\n";
return 1;
}
cout << "Loaded " << fileName << " (" << imageSrc.channels() << " channels)\n";
imageSrc.convertTo(imageSrc, CV_32F, 1 / 255.0, 0.0);
int SliceSizeWidth = imageSrc.cols / 2;
int sliceShiftWidth = imageSrc.cols / 4;
int sliceWidthNumber = (imageSrc.cols / sliceShiftWidth) - 1;
int SliceSizeHeight = imageSrc.rows / 2;
int sliceShiftHeight = imageSrc.rows / 4;
int sliceHeightNumber = (imageSrc.rows / sliceShiftHeight) - 1;
for (int sliceIndexHeight = 0; sliceIndexHeight < sliceHeightNumber; sliceIndexHeight++)
{
for (int sliceIndexWidth = 0; sliceIndexWidth < sliceWidthNumber; sliceIndexWidth++)
{
Mat patchImage = imageSrc(Rect(sliceIndexWidth*sliceShiftWidth, sliceIndexHeight*sliceShiftHeight, SliceSizeWidth, SliceSizeHeight));
Mat patchImageCopy;
patchImage.copyTo(patchImageCopy); // Deep copy => data are contiguous in patchImageCopy
Mat imageBicubic;
resize(patchImageCopy, imageBicubic, Size(2 * patchImage.cols, 2 * patchImage.rows), INTER_CUBIC);
}
}
return 0;
}
My problem is that even if imageBicubic.channels() = 3, when I want to access the second and the third channels, I can't.
I used this line : cout << imageBicubic.at<float>(25,25,1) << endl; in order to see if the second channel was filled, and it seems that it was not (the dims of my image are 756*1200*3). The .exe just stop working. Without the cout, the .exe works fine.
Do I have something to add on the resize fonction to get a 3D Mat at the end ?
Thank you for your time !
I'm trying to use OpenCV SVM classifier in cocos2d-x game. Here's a simple test function:
void HelloWorld::testOpenCV(){
// Load SVM classifier
auto classifierPath = FileUtils::getInstance()->fullPathForFilename("classifier.yml");
cv::Ptr<cv::ml::SVM> svm = cv::ml::StatModel::load<cv::ml::SVM>(classifierPath);
string filename = "test.jpg";
auto img = new Image();
img->initWithImageFile(filename);
int imageSize = (int)img->getDataLen();
int imageXW = img->getWidth();
int imageYW = img->getHeight();
unsigned char * srcData = img->getData();
CCLOG("imageXW=%d, imageYW=%d", imageXW, imageYW);
int ch = imageSize/(imageXW*imageYW);
CCLOG("image=%dch raw data...", ch);
cv::Mat testMat = createCvMatFromRaw(srcData, imageXW, imageYW, ch);
testMat.convertTo(testMat, CV_32F);
// try to predict which number has been drawn
try{
int predicted = svm->predict(testMat);
CCLOG("Recognizing following number -> %d", predicted);
}catch(cv::Exception ex){
}
}
And it gives an output:
imageXW=28, imageYW=28
image=3ch raw data...
OpenCV Error: Assertion failed (samples.cols == var_count && samples.type() == CV_32F) in predict, file /Volumes/build-storage/build/master_iOS-mac/opencv/modules/ml/src/svm.cpp, line 1930
It is based on this tutorial:
https://www.simplicity.be/article/recognizing-handwritten-digits/
Especially on this method:
// Standard library
#include <iostream>
#include <vector>
#include <string>
// OpenCV
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
// POSIX
#include <unistd.h>
/**
* main
**/
int main( int argc, char** argv )
{
//
// Load SVM classifier
cv::Ptr<cv::ml::SVM> svm = cv::ml::StatModel::load<cv::ml::SVM>("classifier.yml");
// read image file (grayscale)
cv::Mat imgMat = cv::imread("test.jpg", 0);
// convert 2d to 1d
cv::Mat testMat = imgMat.clone().reshape(1,1);
testMat.convertTo(testMat, CV_32F);
// try to predict which number has been drawn
try{
int predicted = svm->predict(testMat);
std::cout << std::endl << "Recognizing following number -> " << predicted << std::endl << std::endl;
std::string notifyCmd = "notify-send -t 1000 Recognized: " + std::to_string(predicted);
system(notifyCmd.c_str());
}catch(cv::Exception ex){
}
}
I've ran it in terminal and it worked.
Here's an implementation of createCvMatFromRaw:
cv::Mat HelloWorld::createCvMatFromRaw(unsigned char *rawData, int rawXW, int rawYW, int ch)
{
cv::Mat cvMat( rawYW, rawXW, CV_8UC4); // 8 bits per component, 4 channels
for (int py=0; py<rawYW; py++) {
for (int px=0; px<rawXW; px++) {
int nBasePos = ((rawXW * py)+px) * ch;
cvMat.at<cv::Vec4b>(py, px) = cv::Vec4b(rawData[nBasePos + 0],
rawData[nBasePos + 1],
rawData[nBasePos + 2],
0xFF);
}
}
return cvMat;
}
I've found it here:
http://blog.szmake.net/archives/845
What does this assert mean? Can someone explain it to me? How can I fix this?
The assertion says
OpenCV Error: Assertion failed (samples.cols == var_count && samples.type() == CV_32F)
which means that the sample either doesn't have the right number of columns or doesn't have type CV_32F.
It looks like you forgot the reshape function, so your data violates the first condition. I think in order to apply svm, the data needs to be a vector, i.e. 1 x n matrix.
I have been porting some video processing code to C++ using OpenCV 2.4.3. The following test program closely mimics how my code will read each frame from a video, operate on its contents, and then write new frames to a new video file.
Strangely, the output frames are entirely black when the pixels are set individually, but are written correctly when the entire frame is cloned.
In practice, I'd use the two macros to access and assign desired values, but the sequential scan used in the example shows the idea more clearly.
Does anyone know where I'm going wrong?
test.cpp:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
#define RGB_REF(PR,NC,R,C,CH) (*((PR) + ((3*(NC)*(R)+(C))+(CH))))
#define GRAY_REF(PR,NC,R,C) (*((PR) + (NC)*(R)+(C)))
int main(int argc, char* argv[])
{
string video_path(argv[1]);
cerr << "Video path is " + video_path + "\n";
VideoCapture capture(video_path);
if ( !capture.isOpened() )
{
cerr << "Input file could not be opened\n";
return 1;
} else
{
string output_path(argv[2]);
VideoWriter output;
int ex = (int)capture.get(CV_CAP_PROP_FOURCC);
Size S = Size((int) capture.get(CV_CAP_PROP_FRAME_WIDTH),
(int) capture.get(CV_CAP_PROP_FRAME_HEIGHT));
output.open(output_path,ex,capture.get(CV_CAP_PROP_FPS),S,true);
if ( !output.isOpened() )
{
cerr << "Output file could not be opened\n";
return 1;
}
unsigned int numFrames = (unsigned int) capture.get(CV_CAP_PROP_FRAME_COUNT);
unsigned int m = (unsigned int) capture.get(CV_CAP_PROP_FRAME_HEIGHT);
unsigned int n = (unsigned int) capture.get(CV_CAP_PROP_FRAME_WIDTH);
unsigned char* im = (unsigned char*) malloc(m*n*3*sizeof(unsigned char));
unsigned char* bw = (unsigned char*) malloc(m*n*3*sizeof(unsigned char));
Mat frame(m,n,CV_8UC3,im);
Mat outputFrame(m,n,CV_8UC3,bw);
for (size_t i=0; i<numFrames; i++)
{
capture >> frame;
for (size_t x=0;x<(3*m*n);x++)
{
bw[x] = im[x];
}
output << outputFrame; // blank frames
// output << frame; // works
// output << (outputFrame = frame); // works
}
}
}
When you query a frame from VideoCapture as capture >> frame;, frame is modified. Say, it has a new data buffer. So im no longer points to the buffer of frame.
Try
bm[x] = frame.ptr()[x];
I'm trying to add several images using opencv. I think that my source code should be correct and it compiles without any problems. But when I start the program an error occurs in the for-loop. The problem is that I don't understand why this is happening.
#include <iostream>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <string>
#include <fstream>
#include <cv.h>
#include <highgui.h>
using namespace std;
int get_files(string dir,
vector<string> &files);
int main( int argc, char** argv ){
//---------- Get the names of all *.png files in the directory
string directory = string(".");
vector<string> files = vector<string>();
get_files(directory,files);
//---------- Erase all filenames that aren't *.png files
vector<string> files_format = vector<string>();
for (unsigned int ii = 0; ii < files.size(); ii++) {
files_format.push_back(files[ii]);
string::iterator it;
string format;
files_format[ii].erase(0,files_format[ii].length()-3);
if (files_format[ii] != "png") files.erase(files.begin() + ii);
}
files.erase(files.begin()); // in order to remove the ".." in the beginning
int number_of_files = files.size();
//---------- Create the necessary images
if (files.size() == 0)
return -1;
IplImage* img_firstimage = cvLoadImage(files[0].c_str());
IplImage* img_totalsum = cvCreateImage(cvGetSize(img_firstimage), 8, 1 );
cvCvtColor(img_firstimage, img_totalsum, CV_BGR2GRAY );
//---------- Apply threshold
cvThreshold(img_totalsum, img_totalsum, 150, 1, 1);
//---------- Add all the images
for (unsigned int ii=1; ii < files.size(); ii++){
IplImage* img_load = cvLoadImage(files[ii].c_str());
IplImage* img_add = cvCreateImage(cvGetSize(img_load), 8, 1 );
cvCvtColor(img_load, img_add, CV_BGR2GRAY );
cvThreshold(img_add, img_add, 150, 1, 1);
//----- add the image to the total sum -----
cvAdd(img_totalsum, img_add, img_totalsum);
// ----- release images -----
cvReleaseImage(&img_load);
cvReleaseImage(&img_add);
}
//---------- Invert the total sum image
// -> dense regions are plotted in black
//cvNot(img_totalsum, img_totalsum);
cvNot(img_firstimage, img_firstimage);
//---------- Show the images
cvShowImage("Density Distribution", img_totalsum);
cvShowImage("Negative", img_firstimage);
cvWaitKey(0);
// ----- release images -----
cvReleaseImage(&img_firstimage);
cvReleaseImage(&img_totalsum);
return 0;
}
int get_files(string dir,
vector<string> &files){
DIR *dp;
struct dirent *dirp;
if((dp = opendir(dir.c_str())) == NULL) {
cout << "Error(" << errno << ") opening " << dir << endl;
return errno;
}
while ((dirp = readdir(dp)) != NULL) {
files.push_back(string(dirp->d_name));
}
closedir(dp);
return 0;
It seems, you release your img_add in every loop iteration, but it is created only once. Move the cvReleaseImage(&img_add); instruction outside (directly under) your for loop. That should fix it.
EDIT:
Okay, seems, you fixed that already. Does it work now?
Btw, creating and releasing the img_add inside of your for loop for every newly loaded image is not necessary and is possibly slower, because of the multiple memory allocation and deallocation. You should better allocate it befor entering the loop and release it after the loop.
I solved the problem. I had some other files in the working directory, that weren't *.png files and then the loop didn't work. Absolutely clear that the program couldn't load the other files and work with them... I just don't understand, why the part of the program isn't working that should take care of this problem... Somehow the if (files_format[ii] != "png") files.erase(files.begin() + ii); didn't work properly