I am trying to generate a point cloud with my Minoru3D stereo camera, but it does not work.
The generated points are definitely not correct.
The camera is correctly calibrated.
My rectified images(rec1, rec2), the disparity map(disp) and the depth map(depth):
And the pointcloud:
I create the depth image with reprojectImageTo3D and then read the points at every pixel.
Full Code:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/contrib/contrib.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include "libcam.h"
#include <stdio.h>
#include <fstream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
// The camera properties
int w = 640;
int h = 480;
int fps = 20;
// The images, which are proceeded
Mat img1, img2;
// The grayscale versions of the images
Mat gray1, gray2;
// The disparity and depth map
Mat disparity;
Mat depth(Size(h, w), CV_32FC3);
// The iplImage versions of the images used to get the images from the camera
IplImage *iplImg1 = cvCreateImage(cvSize(w, h), 8, 3), *iplImg2 = cvCreateImage(cvSize(w, h), 8, 3);
// The cameras
Camera cam1("/dev/video0", w, h, fps), cam2("/dev/video1", w, h, fps);
// Load the camera model
Mat CM1, CM2, D1, D2, R, T, E, F, R1, R2, P1, P2, Q;
FileStorage fs("data/stereocalib.yml", FileStorage::READ);
fs["CM1"] >> CM1;
fs["CM2"] >> CM2;
fs["D1"] >> D1;
fs["D2"] >> D2;
fs["R"] >> R;
fs["T"] >> T;
fs["E"] >> E;
fs["F"] >> F;
fs["R1"] >> R1;
fs["R2"] >> R2;
fs["P1"] >> P1;
fs["P2"] >> P2;
fs["Q"] >> Q;
fs.release();
Mat map1x = Mat(h, w, CV_32F);
Mat map1y = Mat(h, w, CV_32F);
Mat map2x = Mat(h, w, CV_32F);
Mat map2y = Mat(h, w, CV_32F);
initUndistortRectifyMap(CM1, D1, R1, P1, cvSize(w, h), CV_32FC1, map1x, map1y);
initUndistortRectifyMap(CM2, D2, R2, P2, cvSize(w, h), CV_32FC1, map2x, map2y);
// The rectified images
Mat imgU1 = Mat(img1.size(), img1.type()), imgU2 = Mat(img2.size(), img2.type());
Ptr<StereoBM> sbm = createStereoBM(16 * 10, 5);
while (true) {
// Get the images from the cameras
cam1.Update();
cam2.Update();
cam1.toIplImage(iplImg1);
cam2.toIplImage(iplImg2);
img1 = cvarrToMat(iplImg1);
img2 = cvarrToMat(iplImg2);
// Rectify
remap(img1, imgU1, map1x, map1y, INTER_LINEAR, BORDER_CONSTANT, Scalar());
remap(img2, imgU2, map2x, map2y, INTER_LINEAR, BORDER_CONSTANT, Scalar());
// Convert the rectified images to grayscale images
cvtColor(imgU1, gray1, CV_BGR2GRAY);
cvtColor(imgU2, gray2, CV_BGR2GRAY);
// Create disparity map
sbm->compute(gray1, gray2, disparity);
// Create depth map
reprojectImageTo3D(disparity, depth, Q, true, CV_32F);
//imshow("img1", img1);
//imshow("img2", img2);
imshow("rec1", gray1);
imshow("rec2", gray2);
imshow("disp", disparity);
imshow("depth", depth);
int key = waitKey(10);
if (key == 'q') {
break;
}
else if (key == 's') {
stringstream output;
for (int x = 0; x < img1.rows; x++) {
for (int y = 0; y < img1.cols; y++) {
Point3f p = depth.at<Point3f>(x, y);
if(p.z >= 10000) continue; // Filter errors
output << p.x << "," << p.y << "," << p.z << endl;
}
}
ofstream outputFile("points");
outputFile << output.str();
outputFile.close();
cout << "saved" << endl;
}
else if (key == 'p') {
waitKey(0);
}
}
destroyAllWindows();
return 0;
}
Related
So I am trying to edit all the frames from input video and than save them to the output. The saved video appears and has the proper filesize but can't open and the imshow inside the while doesn't show the frames at all (only a blank window). I've tried numerous codecs (H264,MJPG,MPEG,MPV4,XVID,CVID) and non of them make it work. What could be the problem? Also, the first function is for converting RGB to YUV and returning the gray channel, while the second one works with HPF and LPF. These functions work on individual images so I don't think they are the problem.
#include <opencv2\opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
Mat KonverzijaRGB2YUV(Mat ulazniFrejm){
int width = ulazniFrejm.cols;
int height = ulazniFrejm.rows;
Mat konvertovan(height, width, CV_8UC3, Scalar(0,0,0));
for(int i=0; i<width; i++){
for(int j=0; j<height; j++){
double R = ulazniFrejm.at<Vec3b>(j,i).val[0];
double G = ulazniFrejm.at<Vec3b>(j,i).val[1];
double B = ulazniFrejm.at<Vec3b>(j,i).val[2];
double Y = 0.299*R + 0.587*G + 0.114*B;
double U = 0.436*(B-Y) / (1-0.114);
double V = 0.615*(R-Y) / (1-0.299);
konvertovan.at<Vec3b>(j,i).val[0] = Y;
konvertovan.at<Vec3b>(j,i).val[1] = U;
konvertovan.at<Vec3b>(j,i).val[2] = V;
}
}
Mat Ykanal[3];
split (konvertovan, Ykanal);
Mat YkanalRGB;
cvtColor(Ykanal[0], YkanalRGB, CV_GRAY2RGB);
return YkanalRGB;
}
Mat Izostravanje(Mat ulazniFrejm){
Mat izostrena;
float valLaplas[] =
{ 0.,-1.,0.,
-1.,4.,-1.,
0.,-1.,0. };
Mat kernelLaplas(Size(3,3), CV_32FC1, valLaplas);
Mat Laplas;
filter2D(ulazniFrejm, Laplas, -1, kernelLaplas);
convertScaleAbs(Laplas, Laplas);
Mat Gaus;
GaussianBlur(ulazniFrejm, Gaus, Size(3,3), 0, 0);
addWeighted(Laplas, 1.4, Gaus, 1.0, 0, izostrena);
return izostrena;
}
int main(int argc, char** argv){
VideoCapture ulazniVideo("esmeralda.mp4");
int brojFrejmova = static_cast<int>(ulazniVideo.get(CV_CAP_PROP_FRAME_COUNT));
if(!ulazniVideo.isOpened()){
cout << "Video se ne moze otvoriti" << endl;
}
waitKey(1000);
Size frameSize = Size((int)ulazniVideo.get(CV_CAP_PROP_FRAME_WIDTH), (int)ulazniVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
int fps = ulazniVideo.get(CV_CAP_PROP_FPS);
int ex = -1;
VideoWriter izlazniVideo;
izlazniVideo.open("esmeralda.mp4", ex, fps, frameSize, true);
int brojac = 0;
while(true){
Mat frame;
ulazniVideo >> frame;
Mat konvertovanFrejm;
konvertovanFrejm = KonverzijaRGB2YUV(frame);
Mat izostrenFrejm;
izostrenFrejm = Izostravanje(konvertovanFrejm);
if(frame.empty()){
break;
}
izlazniVideo << frame;
brojac++;
namedWindow("Video", CV_WINDOW_AUTOSIZE);
imshow("Video", izostrenFrejm);
int waitKey(1000/fps);
}
waitKey(0);
return 0;
}
I am trying to get a calibration program for captured thermal video converted from python to C++, and the first step in the process is binning the pixels in the image down from 480x640 to 240x320, so pixel bins of 2x2. The returned image after binning (using the same logic from the correctly functioning python version) the image being returned is the left half of the image stretched across the width of the image, rather than giving the whole image only at the smaller resolution.
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/videoio/videoio.hpp>
#include <opencv2/video.hpp>
#include <opencv2/imgcodecs.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat binImg(Mat);
int asInt(uint8_t);
uint8_t as8bit(int);
Mat rotate(Mat, double);
int main(int argc, char *argv[]){
VideoCapture cap(argv[1]);
int frameCount = cap.get(cv::CAP_PROP_FRAME_COUNT);
int frameWidth = cap.get(cv::CAP_PROP_FRAME_WIDTH);
int frameHeight = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
Mat buf [frameCount]; //create new array of Mat for the calibrated video
int fc = 0;
VideoWriter video("cppThermalTest.avi",CV_FOURCC('X','V','I','D'), 15, Size(240, 320), false); //create empty video #15fps, 320x240, isColor=false
while (fc < frameCount){
Mat frame(640, 480, CV_8UC1, Scalar(70));
cap >> frame;
Mat temp = binImg(frame);//bin the frame
imshow("test", temp);
imwrite("test.jpg", temp);
waitKey(0);
video.write(temp); //write the binned frame to the video
cout << fc << endl;
fc++;
}
cap.release();
video.release();
return 0;
}
Mat binImg(Mat frame){
int frameWidth = frame.cols / 2; //480 / 2
int frameHeight = frame.rows / 2; //640 / 2
cout << frameHeight << " " << frameWidth << endl;
Mat binFrame(frameHeight, frameWidth, CV_8UC1);
for(int i=0; i<binFrame.rows; i++){
for(int j=0; j<binFrame.cols; j++){
int ul = asInt(frame.at<uint8_t>((2*i),(2*j)));
int bl = asInt(frame.at<uint8_t>(((2*i)+1),(2*j)));
int ur = asInt(frame.at<uint8_t>((2*i), ((2*j)+1)));
int br = asInt(frame.at<uint8_t>(((2*i)+1),((2*j)+1)));
int avg = (ul + ur + bl + br) / 4;
binFrame.at<uint8_t>(i,j) = as8bit(avg); //set the matrix element to the new value
}
}
return binFrame;
}
int asInt(uint8_t val){
//convert unsigned 8 bit int to int
int temp = val;
return temp;
}
uint8_t as8bit(int val){
//convert int to unsigned 8 bit int
uint8_t temp = val;
return temp;
}
Mat rotate(Mat src, double angle){ //rotate function returning mat object with parametres imagefile and angle
Mat dst; //Mat object for output image file
Point2f pt(src.cols/2., src.rows/2.); //point from where to rotate
Mat r = getRotationMatrix2D(pt, angle, 1.0); //Mat object for storing after rotation
warpAffine(src, dst, r, Size(src.cols, src.rows)); ///applie an affine transforation to image.
return dst; //returning Mat object for output image file
}
After playing around with things for a while, I found that when doing "at" calls, specifying 0 as a third parameter (e.g. binFrame.at<uint8_t>(i,j, 0) = as8bit(avg);) fixes the issue.
I am trying to take out the ground and make grids on it for path mapping and insert it back to the image. Here I am using findhomography and warpPerspective functions to do so. But when I switch the points for inserting back the modified plane, everything except the plane becomes black in the image.
I have tried to do it using an intermediate image but the result is the same.
#include "pch.h"
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
struct userdata {
Mat im;
vector<Point2f> points;
};
void mouseHandler(int event, int x, int y, int flags, void* data_ptr)
{
if (event == EVENT_LBUTTONDOWN) {
userdata* data = ((userdata*)data_ptr);
circle(data - > im, Point(x, y), 3, Scalar(0, 0, 255), 5, LINE_AA);
imshow("Image", data - > im);
if (data - > points.size() < 4) {
data - > points.push_back(Point2f(x, y));
}
}
}
int main(int argc, char** argv)
{
// Read source image.
Mat im_src = imread("imagesindoor.jpg");
// Destination image. The aspect ratio of the book is 3/4
Size size(400, 300);
Size size2(im_src.cols, im_src.rows);
Mat im_dst = Mat::zeros(size, CV_8UC3);
// Create a vector of destination points.
vector<Point2f> pts_dst;
pts_dst.push_back(Point2f(0, 0));
pts_dst.push_back(Point2f(size.width - 1, 0));
pts_dst.push_back(Point2f(size.width - 1, size.height - 1));
pts_dst.push_back(Point2f(0, size.height - 1));
// Set data for mouse event
Mat im_temp = im_src.clone();
userdata data;
data.im = im_temp;
cout << "Click on the four corners of the book -- top left first and" <<
endl
<< "bottom left last -- and then hit ENTER" << endl;
// Show image and wait for 4 clicks.
imshow("Image", im_temp);
// Set the callback function for any mouse event
setMouseCallback("Image", mouseHandler, &data);
waitKey(0);
// Calculate the homography
Mat h = getPerspectiveTransform(data.points, pts_dst);
// Warp source image to destination
warpPerspective(im_src, im_dst, h, size);
// changing clor of im_dst
for (int i = 0; i < im_dst.rows; i++) {
for (int j = 0; j < im_dst.cols; j++) {
//apply condition here
im_dst.at<cv::Vec3b>(i, j) = 255;
}
}
Mat p = getPerspectiveTransform(pts_dst, data.points);
warpPerspective(im_dst, im_src, p, size2);
// Show image
//imshow("Image", im_dst);
imshow("Image2", im_src);
waitKey(0);
return 0;
}
addWeighted can be used to blend the current result with the source image to get the expected result.
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
struct userdata {
Mat im;
vector<Point2f> points;
};
void mouseHandler(int event, int x, int y, int flags, void* data_ptr)
{
if (event == EVENT_LBUTTONDOWN) {
userdata* data = ((userdata*)data_ptr);
circle(data-> im, Point(x, y), 3, Scalar(0, 0, 255), 5, LINE_AA);
imshow("Image", data->im);
if (data-> points.size() < 4) {
data-> points.push_back(Point2f(x, y));
}
}
}
int main(int argc, char** argv)
{
// Read source image.
Mat im_src = imread("test.png");
// Destination image. The aspect ratio of the book is 3/4
Size size(400, 300);
Size size2(im_src.cols, im_src.rows);
Mat im_dst = Mat::zeros(size, CV_8UC3);
// Create a vector of destination points.
vector<Point2f> pts_dst;
pts_dst.push_back(Point2f(0, 0));
pts_dst.push_back(Point2f(size.width - 1, 0));
pts_dst.push_back(Point2f(size.width - 1, size.height - 1));
pts_dst.push_back(Point2f(0, size.height - 1));
// Set data for mouse event
Mat im_temp = im_src.clone();
userdata data;
data.im = im_temp;
cout << "Click on the four corners of the book -- top left first and" <<
endl
<< "bottom left last -- and then hit ENTER" << endl;
// Show image and wait for 4 clicks.
imshow("Image", im_temp);
// Set the callback function for any mouse event
setMouseCallback("Image", mouseHandler, &data);
waitKey(0);
// Calculate the homography
Mat h = getPerspectiveTransform(data.points, pts_dst);
// Warp source image to destination
warpPerspective(im_src, im_dst, h, size);
// changing clor of im_dst
for (int i = 0; i < im_dst.rows; i++) {
for (int j = 0; j < im_dst.cols; j++) {
//apply condition here
im_dst.at<cv::Vec3b>(i, j) = 255;
}
}
Mat t;
Mat p = getPerspectiveTransform(pts_dst, data.points);
warpPerspective(im_dst, t, p, size2);
// Show image
//imshow("Image", im_dst);
std::cout << "t :" <<t.cols << ", " <<t.rows <<std::endl;
Mat final;
addWeighted(im_src, 0.5, t, 0.5, 0, final);
imshow("Image2", final);
waitKey(0);
return 0;
}
First of all sorry for my bad english.
So, im using dense optical flow, GunnarFarneback speciffically. The code works fine.
Here's the code:
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/video/tracking.hpp"
#include <vector>
#include <iostream>
using namespace std;
using namespace cv;
// Display the results of the matches
//
int main(int argc, char** argv)
{
cv::Mat res, img1, img2, img2Original, img2OriginalC;
cv::VideoWriter writer;
cv::VideoCapture cap;
//cv::VideoCapture cap("prueba1.mp4");
// cap.open(std::string(argv[1]));
cap.open(0);
cv::namedWindow("cat", cv::WINDOW_AUTOSIZE);
cap >> img1;
cvtColor(img1, img1, COLOR_BGR2GRAY);
double fps = cap.get(cv::CAP_PROP_FPS);
//cv::Size tamano((int)cap.get(cv::CAP_PROP_FRAME_WIDTH), (int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));
Size S = Size((int) cap.get(CV_CAP_PROP_FRAME_WIDTH),(int) cap.get(CV_CAP_PROP_FRAME_HEIGHT));
writer.open("mouse.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, S);
for (;;) {
cap >> img2;
if (img2.empty()) break;
img2.copyTo(img2OriginalC);
cvtColor(img2, img2, COLOR_BGR2GRAY);
img2.copyTo(img2Original);
cv::calcOpticalFlowFarneback(img1, img2, res, .4, 1, 12, 2, 8, 1.2, 0);
for (int y = 0; y < img2.rows; y += 5) {
for (int x = 0; x < img2.cols; x += 5)
{
// get the flow from y, x position * 3 for better visibility
const Point2f flowatxy = res.at<Point2f>(y, x) * 1;
// draw line at flow direction
line(img2OriginalC, Point(x, y), Point(cvRound(x + flowatxy.x), cvRound(y + flowatxy.y)), Scalar(255, 0, 0));
// draw initial point
circle(img2OriginalC, Point(x, y), 1, Scalar(0, 0, 0), -1);
}
}
img2Original.copyTo(img1);
imshow("cat", img2OriginalC);
writer << img2OriginalC;
cout <<"Fps"<<endl;
cout <<fps<< endl;
for( int i=3; i>=0; i--)
{
//cout<< res << endl;
//return 0;
}
if (cv::waitKey(1) == 27) break;
}
cap.release();
return 0;
}
i think i know whats the output matrix but im not sure at all. Also,i dont know what does the values mean, finally does anyone knows how to use that output data??
Thanks
I keep getting an assertion failed(0 <= i && i < (int)vv.size())in cv::_InputArray::getMat, in file matrix.cpp when trying to run projectPoints. I have checked everything I can think of but I can't work out what's wrong. My guess is something went wrong with the calibratecamera but I don't know how I would find out what is wrong exactly. Here is my code, thanks.
using namespace cv;
using namespace std;
std::vector<cv::Point3f> Generate3DPoints()
{
std::vector<cv::Point3f> points;
float x,y,z;
x=.5;y=.5;z=.5;
points.push_back(cv::Point3f(x,y,z));
x=0;y=0;z=0;
points.push_back(cv::Point3f(x,y,z));
x=-0;y=0;z=.5;
points.push_back(cv::Point3f(x,y,z));
x=0;y=.5;z=.5;
points.push_back(cv::Point3f(x,y,z));
x=0;y=-.5;z=0;
points.push_back(cv::Point3f(x,y,z));
x=.5;y=0;z=.5;
points.push_back(cv::Point3f(x,y,z));
x=.5;y=0;z=0;
points.push_back(cv::Point3f(x,y,z));
/*
for(unsigned int i = 0; i < points.size(); ++i)
{
std::cout << points[i] << std::endl;
}
*/
return points;
}
int main()
{
int numBoards = 4;
int numCornersHor = 6;
int numCornersVer = 9;
int numSquares = numCornersHor * numCornersVer;
Size board_sz = Size(numCornersHor, numCornersVer);
VideoCapture capture = VideoCapture(0);
vector<vector<Point3f>> object_points;
vector<vector<Point2f>> imagePoints;
vector<vector<Point2f>> image_points;
vector<Point3f> objectPoints1 = Generate3DPoints();
vector<Point2f> corners;
int successes=0;
Mat image;
Mat gray_image;
//capture >> image;
Sleep(1000);
capture.read(image);
imshow("Welcome", image);
vector<Point3f> obj;
for(int j=0;j<numSquares;j++)
obj.push_back(Point3f(j/numCornersHor, j%numCornersHor, 0.0f));
while(successes<numBoards)
{
cvtColor(image, gray_image, CV_BGR2GRAY);
bool found = findChessboardCorners(image, board_sz, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
if(found)
{
cornerSubPix(gray_image, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1));
drawChessboardCorners(gray_image, board_sz, corners, found);
cout << "SUCESS\n";
}
else
cout << "FAIL\n";
imshow("win1", image);
imshow("win2", gray_image);
capture.read(image);
image_points.push_back(corners);
object_points.push_back(obj);
printf("Snap stored!\n");
char continues;
cout << "Press c to continue\n";
cin >> continues;
successes++;
//if(successes>=numBoards)
// break;
}
Mat intrinsic = Mat(3, 3, CV_32FC1);
Mat distCoeffs;
vector<Mat> rvecs;
vector<Mat> tvecs;
intrinsic.ptr<float>(0)[0] = 1;
intrinsic.ptr<float>(1)[1] = 1;
calibrateCamera(object_points, image_points, image.size(), intrinsic, distCoeffs, rvecs, tvecs);
cout << "Done\n";
projectPoints(objectPoints1, rvecs, tvecs, intrinsic, distCoeffs, imagePoints);
cout << "done2";
return 0;
}
You are trying to pass rvecs and tvecs to the function projectPoints, which expects Mat and not vector<Mat>.
Basically, the calibrateCamera function estimates the intrinsics matrix and distortion coefficients of the camera using several images of a chessboard. The function also returns multiple versions of the extrinsics parameters (rotation+translation), one for each image you used. These extrinsic parameters are stored in rvecs and tvecs.
However, you want to project the 3D points in only one of these images, so you should choose what set of extrinsic parameters you want (i.e. rvecs[i] and tvecs[i], i corresponding to the image in which you want to project your object) and call projectPoints for these extrinsic parameters only, not the whole vectors<Mat>.