Isolate object to better detect it
Hello everyone, it's me again: i'm trying to detect dome trees in a pictures and I tryed different ways. At the end I chose a BOW+SVM approach, by creating a dictionary and then applying it to the .train(...) of my SVM. I found out that this isn't enough for what I have to do, since classification gives me wrong result. So I tried a treshold on my test images by applying a clustering for colors, but of course, grass is detected too, so it's not very helpful. My training images (for dictionary and SVM training) are all .png images (so tress without background) and that's why I'm trying to segment my test images to isolate trees. I have tried some basic OpenCV segmentation tecniques (found here) but they don't seem to work. Here's my code:
Mat dictionary;
FileStorage fs("myDictionary.yml", FileStorage::READ);
fs["vocabulary"] >> dictionary;
fs.release();
Ptr<SIFT> detector = SIFT::create(); //detector to detect SIFT features
Ptr<DescriptorExtractor> extractor = SIFT::create();
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
BOWImgDescriptorExtractor bowDE(extractor, matcher);
bowDE.setVocabulary(dictionary);
cout << "extracting histograms in the form of BOW for each Training image " << endl;
Mat labels(0, 1, CV_32S);
cout << labels.size() << endl;
int dictSize = 200;
Mat trainingData;
int k = 0;
vector<KeyPoint> keypoint;
Mat bowDescriptor;
Mat img;
vector<String> fn;
glob("C:/Users/albma/Desktop/train/*.png", fn, true);
for (size_t i = 0; i < fn.size(); i++) { //trees: label = 1
printf("Training Image = %s\n", fn[i]);
img = imread(fn[i], 0);
detector->detect(img, keypoint); //detect keypoints
bowDE.compute(img, keypoint, bowDescriptor); //compute descriptors
trainingData.push_back(bowDescriptor);
labels.push_back((int)1); //push labels in a matrix.. 1
}
cout << trainingData.size() << endl;
cout << labels.size() << endl;
//SVM Part
Ptr<ml::SVM> svm = ml::SVM::create();
svm->setType(SVM::ONE_CLASS);
svm->setNu(0.5);
/*svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));*/
printf("Training SVM\n");
Ptr<TrainData> td = TrainData::create(trainingData, ROW_SAMPLE, labels); //start training SVM
svm->train(td);
Mat testData(0, dictSize, CV_32FC1);
k = 0;
vector<KeyPoint> keypoint2;
Mat bowDescriptor2;
printf("Training Done... loading Test images \n");
vector<String> fnb;
glob("C:/Users/albma/Desktop/Università/Computer Vision/final_project_test/Benchmark_step_1/*.jpg", fnb, true);
Mat results(0, 1, CV_32FC1);
Mat segm;
Mat test = imread("Figure 1.jpg");
inRange(test, Scalar(0, 23, 0), Scalar(11, 255, 34), segm);
imshow("test", segm);
for (int i = 0; i < fnb.size(); i++) {
printf("Test Image = %s\n", fnb[i]);
img = imread(fnb[i]);
//--------------->COLOR_SEGMENTATION
Mat data;
img.convertTo(data, CV_32F);
data = data.reshape(1, data.total());
Mat labels, centers;
kmeans(data, 8, labels, TermCriteria(TermCriteria::MAX_ITER, 10, 1.0), 3,
KMEANS_PP_CENTERS, centers);
centers = centers.reshape(3, centers.rows);
data = data.reshape(3, data.rows);
Vec3f *p = data.ptr<Vec3f>();
for (size_t i = 0; i < data.rows; i++) {
int center_id = labels.at<int>(i);
p[i] = centers.at<Vec3f>(center_id);
}
img = data.reshape(3, img.rows);
img.convertTo(img, CV_8U);
inRange(img, Scalar(0, 23, 0), Scalar(11, 255, 34), segm ...
Another strategy I'm trying is to delete the grass part in the image treshold (maybe by selecting only "dense" white part) and then get back to the original image by applyng bitwise_and(...), but don't know how to implement it. Also, am i supposed to make transparent the black part of the treshold?
I managed to get only the trees in the treshold, however I only get non-trees labels on every test pic... don't get why