Unable to detect ArUco markers with OpenCV 3.1.0 - c++

I am trying to code a simple C++ routine to first write a predefined dictionary of ArUco markers (e.g. 4x4_100) to a folder and then detect ArUco markers in a specific image selected from the folder using OpenCV 3.1 and Visual Studio 2017. I have compiled all the OpenCV-contrib libraries required to use ArUco markers. My routine builds without any error, but I am having trouble detecting the markers even after supplying all the correct arguments (e.g. image, Dictionary, etc.) to the in-built "aruco::detectMarkers" function. Could you please help me understand what`s wrong with my approach? Below is a minimal working example and the test image is attached here "4x4Marker_40.jpg":
#include "opencv2\core.hpp"
#include "opencv2\imgproc.hpp"
#include "opencv2\imgcodecs.hpp"
#include "opencv2\aruco.hpp"
#include "opencv2\highgui.hpp"
#include <sstream>
#include <fstream>
#include <iostream>
using namespace cv;
using namespace std;
// Function to write ArUco markers
void createArucoMarkers()
{
// Define variable to store the output markers
Mat outputMarker;
// Choose a predefined Dictionary of markers
Ptr< aruco::Dictionary> markerDictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
// Write each of the markers to a '.jpg' image file
for (int i = 0; i < 50; i++)
{
aruco::drawMarker(markerDictionary, i, 500, outputMarker, 1);
ostringstream convert;
string imageName = "4x4Marker_";
convert << imageName << i << ".jpg";
imwrite(convert.str(), outputMarker);
}
}
// Main body of the routine
int main(int argv, char** argc)
{
createArucoMarkers();
// Read a specific image
Mat frame = imread("4x4Marker_40.jpg", CV_LOAD_IMAGE_UNCHANGED);
// Define variables to store the output of marker detection
vector<int> markerIds;
vector<vector<Point2f>> markerCorners, rejectedCandidates;
// Define a Dictionary type variable for marker detection
Ptr<aruco::Dictionary> markerDictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
// Detect markers
aruco::detectMarkers(frame, markerDictionary, markerCorners, markerIds);
// Display the image
namedWindow("Webcam", CV_WINDOW_AUTOSIZE);
imshow("Webcam", frame);
// Draw detected markers on the displayed image
aruco::drawDetectedMarkers(frame, markerCorners, markerIds);
cout << "\nmarker ID is:\t"<<markerIds.size();
waitKey();
}

There are a few problems in your code:
You are displaying the image with imshow before calling drawDetectedMarkers so you'll never see the detected marker.
You are displaying the size of the markerIds vector instead of the value contained within it.
(This is the main problem) Your marker has no white space around it so it's impossible to detect.
One suggestion: use forward slashes, not backslashes in your #include statements. Forward slashes work everywhere, backslashes only work on Windows.
This worked on my machine. Note that I loaded the image as a color image to make it easier to see the results of drawDetectedMarkers.
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/aruco.hpp>
#include <opencv2/highgui.hpp>
#include <sstream>
#include <fstream>
#include <iostream>
using namespace cv;
using namespace std;
// Function to write ArUco markers
void createArucoMarkers()
{
// Create image to hold the marker plus surrounding white space
Mat outputImage(700, 700, CV_8UC1);
// Fill the image with white
outputImage = Scalar(255);
// Define an ROI to write the marker into
Rect markerRect(100, 100, 500, 500);
Mat outputMarker(outputImage, markerRect);
// Choose a predefined Dictionary of markers
Ptr< aruco::Dictionary> markerDictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
// Write each of the markers to a '.jpg' image file
for (int i = 0; i < 50; i++)
{
//Draw the marker into the ROI
aruco::drawMarker(markerDictionary, i, 500, outputMarker, 1);
ostringstream convert;
string imageName = "4x4Marker_";
convert << imageName << i << ".jpg";
// Note we are writing outputImage, not outputMarker
imwrite(convert.str(), outputImage);
}
}
// Main body of the routine
int main(int argv, char** argc)
{
createArucoMarkers();
// Read a specific image
Mat frame = imread("4x4Marker_40.jpg", CV_LOAD_IMAGE_COLOR);
// Define variables to store the output of marker detection
vector<int> markerIds;
vector<vector<Point2f>> markerCorners, rejectedCandidates;
// Define a Dictionary type variable for marker detection
Ptr<aruco::Dictionary> markerDictionary = aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME::DICT_4X4_50);
// Detect markers
aruco::detectMarkers(frame, markerDictionary, markerCorners, markerIds);
// Display the image
namedWindow("Webcam", CV_WINDOW_AUTOSIZE);
// Draw detected markers on the displayed image
aruco::drawDetectedMarkers(frame, markerCorners, markerIds);
// Show the image with the detected marker
imshow("Webcam", frame);
// If a marker was identified, show its ID
if (markerIds.size() > 0) {
cout << "\nmarker ID is:\t" << markerIds[0] << endl;
}
waitKey(0);
}

Related

Wrong cv::face FacemarkLBF instantiation

I am using OpenCV 4.4.0 on Ubuntu 20.04 with the installed latest opencv_contrib extra modules. For detecting the face landmarks (based on this tutorial) I use the following #include and namespace sections related to the extra face module :
#include <opencv2/face.hpp>
using namespace cv::face;
The face.hpp file is detected (therefore I assume correct installation of the opencv_contrib modules), but e.g. the line
Ptr<facemark> facemark = FacemarkLBF::create();
throws an error
error: ‘facemark’ was not declared in this scope
I have already tried installing the extra modules with both cmake-gui and with the cmake terminal command. The results are the same. I assume there is an error related to the namespace cv::face. Any ideas on what kind of mistake I am doing here?
The minimal code is here:
#include <opencv2/opencv.hpp>
#include <opencv2/face.hpp>
#include "drawLandmarks.hpp"
using namespace std;
using namespace cv;
using namespace cv::face;
int main(int argc,char** argv)
{
// Load Face Detector
CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml");
// Create an instance of Facemark
Ptr<facemark> facemark = FacemarkLBF::create();
// Load landmark detector
facemark->loadModel("lbfmodel.yaml");
// Set up webcam for video capture
VideoCapture cam(0);
// Variable to store a video frame and its grayscale
Mat frame, gray;
// Read a frame
while(cam.read(frame))
{
// Find face
vector<rect> faces;
// Convert frame to grayscale because
// faceDetector requires grayscale image.
cvtColor(frame, gray, COLOR_BGR2GRAY);
// Detect faces
faceDetector.detectMultiScale(gray, faces);
// Variable for landmarks.
// Landmarks for one face is a vector of points
// There can be more than one face in the image. Hence, we
// use a vector of vector of points.
vector< vector<point2f> > landmarks;
// Run landmark detector
bool success = facemark->fit(frame,faces,landmarks);
if(success)
{
// If successful, render the landmarks on the face
for(int i = 0; i < landmarks.size(); i++)
{
drawLandmarks(frame, landmarks[i]);
}
}
// Display results
imshow("Facial Landmark Detection", frame);
// Exit loop if ESC is pressed
if (waitKey(1) == 27) break;
}
return 0;
}
As #john and #idclev 463035818 have suggested, the way for creating an instance of Facemark is
Ptr<FacemarkLBF> facemark = FacemarkLBF::create();
e.g. if I want to call it facemark.

Overlay using opencv using C++

My question is about trying to fixing the italized line so that my overlay will work properly and instead of black pixels there are white pixels based on my conditional statement. I have tried several things such as using different types such as:
out1.at<Vec3b>(i,j)[0]=image.at<Vec3b>(i,j)[0];
out1.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[1];
out1.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[2];
But I got a heap error. I believe I am really close but I need some advice or guidance. Please excuse any errors that I have made posting for this is my first post.
Here is my code.
#include <iostream>
#include <stdint.h>
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
using namespace std;
using namespace cv;
int main(int argv, char** argc)
{
Mat image; // new blank image
Mat image2;
Mat out1;
image2 = cv::imread("test2.bmp",CV_LOAD_IMAGE_GRAYSCALE); // read the file
image = cv::imread("test1.bmp",CV_LOAD_IMAGE_GRAYSCALE);
if (!image.data) // error handling if file does not load
{
cout<< "Image 1 not loaded";
return -1;
}
if (!image2.data)
{
cout << "Image 2 not loaded";
return -1;
}
// resize images to make sure all images is the same size
cv::resize(image2, image2, image.size());
cv::resize(image2, out1, image.size());
// copying content of overlay image to output file
//image2.copyTo(out1);
out1 = image2.clone();
// for loop comparing pixels to original image
for (int i =0; i < out1.rows; i++)
{
for(int j =0; j < out1.cols; j++)
{
//Vec3b color = image.at<Vec3b>(Point(i,j));
if(out1.at<uchar>(i,j)==0 && out1.at<uchar>(i,j) ==0 &&
out1.at<uchar>(i,j)==0)
{
out1.at<Vec3b>(i,j)[0]=255; // blue channel
out1.at<Vec3b>(i,j)[1]=255; // green channel
out1.at<Vec3b>(i,j)[2]=255; // red channel
}
else
*out1.at<uchar>(i,j) = image.at<uchar>(i,j);*
}
}
cv::imwrite("out1.bmp",out1); // save to output file
namedWindow("Display window", CV_WINDOW_AUTOSIZE);// creat a window to
display w/label
imshow("Display window",out1); // show image inside display window
waitKey(0);
return 0;
}
My image is close to being overlayed correctly. My issue is that the
pixels shows up black instead of white due to a certain line in my
program

Hough Transformation OPENCV C++

http://inside.mines.edu/~whoff/courses/EENG512/lectures/HoughInOpenCV.pdf
Hi, i am going through the pdf tutorial in the link above.
I encounter problem on page 6 of the slides.
As we seee that the output of the code after inserting the canny edge detector, it should trace out all the edges on a photo.
I cannot get what is shown at page 6.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
printf("Hello world\n");
// read an image
Mat imgInput = imread("a.png");
// create image window named "My Image"
namedWindow("My Image");
// Convert to gray if necessary
if (imgInput.channels() == 3)
cv::cvtColor(imgInput, imgInput, CV_BGR2GRAY);
// Apply Canny edge detector
Mat imgContours;
double thresh = 105; // try different values to see effect
Canny(imgInput, imgContours, 0.4*thresh, thresh); // low, high threshold
// show the image on window
imshow("My Image", imgInput);
// wait for xx ms (0 means wait until keypress)
waitKey(5000);
return 0;
}
And also, there is a line double thresh = xxx;//try different values
What values should i put? and what are the values mean?
Thank you
Just replace your imshow function with ,
imshow("My Image", imgContours);
and you can use thresh value approximately around 200.
Change threshold value and see effect of it and according to that you can select your threshold value.
The imgContours is your output map with all the edges. You should use imshow with imgContours.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
printf("Hello world\n");
// read an image
Mat imgInput = imread("a.png");
// create image window named "My Image"
namedWindow("My Image");
// Convert to gray if necessary
if (imgInput.channels() == 3)
cv::cvtColor(imgInput, imgInput, CV_BGR2GRAY);
// Apply Canny edge detector
Mat imgContours;
double thresh = 105; // try different values to see effect
Canny(imgInput, imgContours, 0.4*thresh, thresh); // low, high threshold
// show the image on window
imshow("My Image", imgContours);
// wait for xx ms (0 means wait until keypress)
waitKey(5000);
return 0;
}
Reference:
http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=canny#canny

opencv imshow show only the image

I've switched from Ubuntu to Windows for my opencv project and while displaying an image using the imshow function the image is displayed but the other details like x axis and y axis information and the intensity values were not shown in the window.
The same code under the Ubuntu build works perfectly. Here is my code:
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main()
{
cv::Mat imgrgb = imread("C:\\Users\\Len\\Documents\\project\\Images\\1-11.jpg", CV_LOAD_IMAGE_COLOR);
// Check that the image read is a 3 channels image and not empty
CV_Assert(imgrgb.channels() == 3);
if (imgrgb.empty()) {
cout << "Image is empty. Specify correct path" << endl;
return -1;
}
cv::cvtColor(imgrgb, img, CV_BGR2GRAY);
namedWindow("Test", cv::WINDOW_AUTOSIZE);
imshow("Test", imgrgb);
waitKey(0);
}
So, how can I display the intensity values along with the current x and y axis information?

watershed segmentation opencv xcode

I am now learning a code from the opencv codebook (OpenCV 2 Computer Vision Application Programming Cookbook): Chapter 5, Segmenting images using watersheds, page 131.
Here is my main code:
#include "opencv2/opencv.hpp"
#include <string>
using namespace cv;
using namespace std;
class WatershedSegmenter {
private:
cv::Mat markers;
public:
void setMarkers(const cv::Mat& markerImage){
markerImage.convertTo(markers, CV_32S);
}
cv::Mat process(const cv::Mat &image){
cv::watershed(image,markers);
return markers;
}
};
int main ()
{
cv::Mat image = cv::imread("/Users/yaozhongsong/Pictures/IMG_1648.JPG");
// Eliminate noise and smaller objects
cv::Mat fg;
cv::erode(binary,fg,cv::Mat(),cv::Point(-1,-1),6);
// Identify image pixels without objects
cv::Mat bg;
cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),6);
cv::threshold(bg,bg,1,128,cv::THRESH_BINARY_INV);
// Create markers image
cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0));
markers= fg+bg;
// Create watershed segmentation object
WatershedSegmenter segmenter;
// Set markers and process
segmenter.setMarkers(markers);
segmenter.process(image);
imshow("a",image);
std::cout<<".";
cv::waitKey(0);
}
However, it doesn't work. How could I initialize a binary image? And how could I make this segmentation code work?
I am not very clear about this part of the book.
Thanks in advance!
There's a couple of things that should be mentioned about your code:
Watershed expects the input and the output image to have the same size;
You probably want to get rid of the const parameters in the methods;
Notice that the result of watershed is actually markers and not image as your code suggests; About that, you need to grab the return of process()!
This is your code, with the fixes above:
// Usage: ./app input.jpg
#include "opencv2/opencv.hpp"
#include <string>
using namespace cv;
using namespace std;
class WatershedSegmenter{
private:
cv::Mat markers;
public:
void setMarkers(cv::Mat& markerImage)
{
markerImage.convertTo(markers, CV_32S);
}
cv::Mat process(cv::Mat &image)
{
cv::watershed(image, markers);
markers.convertTo(markers,CV_8U);
return markers;
}
};
int main(int argc, char* argv[])
{
cv::Mat image = cv::imread(argv[1]);
cv::Mat binary;// = cv::imread(argv[2], 0);
cv::cvtColor(image, binary, CV_BGR2GRAY);
cv::threshold(binary, binary, 100, 255, THRESH_BINARY);
imshow("originalimage", image);
imshow("originalbinary", binary);
// Eliminate noise and smaller objects
cv::Mat fg;
cv::erode(binary,fg,cv::Mat(),cv::Point(-1,-1),2);
imshow("fg", fg);
// Identify image pixels without objects
cv::Mat bg;
cv::dilate(binary,bg,cv::Mat(),cv::Point(-1,-1),3);
cv::threshold(bg,bg,1, 128,cv::THRESH_BINARY_INV);
imshow("bg", bg);
// Create markers image
cv::Mat markers(binary.size(),CV_8U,cv::Scalar(0));
markers= fg+bg;
imshow("markers", markers);
// Create watershed segmentation object
WatershedSegmenter segmenter;
segmenter.setMarkers(markers);
cv::Mat result = segmenter.process(image);
result.convertTo(result,CV_8U);
imshow("final_result", result);
cv::waitKey(0);
return 0;
}
I took the liberty of using Abid's input image for testing and this is what I got:
Below is the simplified version of your code, and it works fine for me. Check it out :
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
using namespace std;
int main ()
{
Mat image = imread("sofwatershed.jpg");
Mat binary = imread("sofwsthresh.png",0);
// Eliminate noise and smaller objects
Mat fg;
erode(binary,fg,Mat(),Point(-1,-1),2);
// Identify image pixels without objects
Mat bg;
dilate(binary,bg,Mat(),Point(-1,-1),3);
threshold(bg,bg,1,128,THRESH_BINARY_INV);
// Create markers image
Mat markers(binary.size(),CV_8U,Scalar(0));
markers= fg+bg;
markers.convertTo(markers, CV_32S);
watershed(image,markers);
markers.convertTo(markers,CV_8U);
imshow("a",markers);
waitKey(0);
}
Below is my input image :
Below is my output image :
See the code explanation here : Simple watershed Sample in OpenCV
I had the same problem as you, following the exact same code sample of the cookbook (great book btw).
Just to place the matter I was coding under Visual Studio 2013 and OpenCV 2.4.8. After a lot of searching and no solutions I decided to change the IDE.
It's still Visual Studio BUT it's 2010!!!! And boom it works!
Becareful of how you configure Visual Studio with OpenCV. Here's a great tutorial for installation here
Good day to all