I am trying to create a point cloud using a stereo camera arrangement (calibrated and rectified), a disparity map, and Point Cloud Library. Below is a brief description of my C++ code that is supposed to generate a point cloud using the disparity map.
#include <iostream>
#include <fstream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/ximgproc.hpp>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/vtk.h>
using namespace std;
using namespace cv;
using namespace cv::ximgproc;
using namespace pcl;
using namespace pcl::visualization;
boost::shared_ptr<PCLVisualizer> rgbVis (PointCloud<PointXYZRGB>::ConstPtr cloud)
{
boost::shared_ptr<PCLVisualizer> viewer (new PCLVisualizer ("3D Viewer"));
viewer->setBackgroundColor (0, 0, 0);
PointCloudColorHandlerRGBField<PointXYZRGB> rgb(cloud);
viewer->addPointCloud<PointXYZRGB> (cloud, rgb, "sample cloud");
viewer->setPointCloudRenderingProperties (PCL_VISUALIZER_POINT_SIZE, 3, "sample cloud");
return (viewer);
}
/* Some other functions */
int main()
{
.....
.....
int l, r;
cout << "Enter CAM index for Left Camera ";
cin >> l;
cout << endl << "Enter CAM index for Right Camera ";
cin >> r;
VideoCapture leftCam(l);
VideoCapture rightCam(r);
........
........
boost::shared_ptr<PCLVisualizer> viewer;
bool proceed = true;
while(proceed)
{
........
........
PointCloud<PointXYZRGB>::Ptr pointCloud(new PointCloud<PointXYZRGB>());
Mat xyz;
reprojectImageTo3D(disparityMap, xyz, q);
pointCloud->width = static_cast<uint32_t>(disparityMap.cols);
pointCloud->height = static_cast<uint32_t>(disparityMap.rows);
pointCloud->is_dense = false;
PointXYZRGB tempPoint;
for(int i = 0; i < disparityMap.rows; i++)
{
uchar* rgb_ptr = rightUndistorted.ptr<uchar>(i);
uchar* disp_ptr = disparityMap.ptr<uchar>(i);
double* xyz_ptr = xyz.ptr<double>(i);
for(int j = 0; j < disparityMap.cols; j++)
{
uchar d = disp_ptr[j];
if(d == 0)
continue;
Point3f p = xyz.at<Point3f>(i, j);
tempPoint.x = p.x;
tempPoint.y = p.y;
tempPoint.z = p.z;
tempPoint.b = rgb_ptr[3 * j];
tempPoint.g = rgb_ptr[3 * j + 1];
tempPoint.r = rgb_ptr[3 * j + 2];
pointCloud->points.push_back(tempPoint);
}
}
viewer = rgbVis(pointCloud);
if(waitKey(50) == 'q')
proceed = false;
}
destroyAllWindows();
return 0;
}
I run the following terminal command to compile this .cpp file...
g++ -std=c++14 d2pc.cpp -o d2pc `pkg-config --cflags --libs opencv pcl_io-1.11 pcl_visualization-1.11` -lboost_system
This generates the following error message...
/usr/local/include/pcl-1.11/pcl/visualization/point_cloud_geometry_handlers.h:48:10: fatal error: vtkSmartPointer.h: No such file or directory
#include <vtkSmartPointer.h>
^~~~~~~~~~~~~~~~~~~
compilation terminated.
I thought that installing Vtk from here might help solve the issue, but it didn't help.
How to tackle this issue? I am using OpenCV 3.4.10 in Ubuntu 18.04
First build and install vtk:
Build
tar xf VTK-9.0.1.tar.gz
cd VTK-9.0.1
mkdir build && cd build
cmake ..
make -j
Install
(if you have a different preferred place for installations than ~/.local, just change insdir below)
insdir=$(echo ~/.local)
mkdir $insdir
cmake --install . --prefix $insdir
Then add the include path (-I $insdir/include/vtk-9.0), the library path (-L $insdir/lib64 or possibly $insdir/lib on a 32 bit machine) and vtk libraries (-llibname1 ... -llibnameX) to your compilation command.
Example:
allvtklibs=$(ls $insdir/lib64/libvtk*.so | sed -E 's,^.*/lib(.*)\.so$,-l\1,')
g++ -std=c++14 d2pc.cpp -o d2pc -I $insdir/include/vtk-9.0 -L $insdir/lib64 $(pkg-config --cflags --libs opencv pcl_io-1.11 pcl_visualization-1.11) -Wl,-rpath=$insdir/lib64 $allvtklibs -lboost_system
Related
I haven't ever used ffmpeg on my own laptop. All's ok at work, but here I met an ugly problem: library works but helpless:)
Ubuntu 18.04, ffmpeg 4.1 (downloaded sources, ./configure, make, sudo make install), it seems to be ok.
Application returns:
File /home/ahlininv/Desktop/video_example.mp4 is encodec with '' codec, w = 0, h = 0
I ran it under debugger. If I set format to zero, pointer changes after calling avformat_open_input(&format, file, 0, &dict), so it works and maybe works correct.
Maybe it plays any role that compiler says that av_register_all, avcodec_register_all are deprecated, but I thought it's not significant problem.
I tried to change version of ffmpeg (tried to install it with apt-get, version 3.somenumber is available), nothing changed.
I tried to run another video file (.avi), nothing changed, too.
Guys, help=) How to this file's info correctly?
main.cpp:
#include "filereader.h"
int main(int argc, char** argv) {
std::string filename = "/home/ahlininv/Desktop/video_example.mp4";
std::string codec;
int w, h;
bool open_ok = get_file_info(filename.c_str(), codec, w, h);
if (!open_ok) {
std::cout << "Failed to open file" << "\n";
return 1;
}
std::cout << "File " << filename << " is encoded with '" << codec << "' codec, w = " << w << ", h = " << h << "\n";
return 0;
}
filereader.h:
#ifndef FILEREADER_H
#define FILEREADER_H
#include <string>
#include <iostream>
extern "C" {
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include "libavcodec/avcodec.h"
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
}
bool get_file_info(const char* file, std::string& codec, int& w, int& h);
#endif // FILEREADER_H
filereader.cpp
#include "filereader.h"
bool get_file_info(const char* file, std::string& codec, int& w, int& h)
{
codec = "";
w = h = 0;
av_register_all();
avcodec_register_all();
AVDictionary* dict = 0;
AVFormatContext* format = avformat_alloc_context();
char errbuf[256];
int r = avformat_open_input(&format, file, 0, &dict);
if (r!=0){
av_strerror(r, errbuf, sizeof(errbuf));
std::cout << "avformat_open_input error: " << errbuf << "\n";
}
if (r == AVERROR(EIO) || r == AVERROR(ENOEXEC) || !format)
return false;
for (size_t c = 0; c < format->nb_streams; ++c)
{
if (format->streams[c]->codecpar && format->streams[c]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
if (format->streams[c]->codecpar->codec_id != AV_CODEC_ID_NONE &&
format->streams[c]->codecpar->codec_id != AV_CODEC_ID_RAWVIDEO)
{
w = format->streams[c]->codecpar->width;
h = format->streams[c]->codecpar->height;
codec = avcodec_get_name(format->streams[c]->codecpar->codec_id);
}
}
}
avformat_close_input(&format);
return true;
}
Compile:
g++ -o filereader main.cpp filereader.cpp -lavutil -lavformat -lavcodec -lavdevice -lz -lm -pthread -lswresample -lm -lz -I /usr/local/include/ -Wl,-rpath /usr/lib/x86_64-linux-gnu/
Can you add these lines Before for loop on filereader.cpp to see if it makes any difference.
if (avformat_find_stream_info(format, NULL) < 0)
{
//handle error
}
I am quite new to c++ compilation. I am trying to work on a simple problem using opencv where I read a video file and display it.
My code looks like:
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include "opencv2/opencv.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <ctype.h>
#include <unistd.h>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <list>
#include <string>
using namespace cv;
IplImage* image = 0;
IplImage* prev_image = 0;
int show = 1;
int main( int argc, char** argv )
{
int frameNum = 0;
char* video = argv[1];
VideoCapture capture(video);
if( !capture.isOpened() ) {
printf( "Could not initialize capturing..\n" );
return -1;
}
if( show == 1 )
cvNamedWindow( "Video", 0 );
while( true ) {
IplImage* frame = 0;
int i, j, c;
// get a new frame
//frame = cvQueryFrame( capture );
Mat mat_img;
capture >> mat_img;
IplImage frame1 = mat_img.operator IplImage();
frame = &frame1;
if( !frame )
break;
if( !image ) {
image = cvCreateImage( cvSize(frame->width,frame->height), 8, 3 );
image->origin = frame->origin;
}
cvCopy( frame, image, 0 );
if( show == 1 ) {
cvShowImage( "Video", image);
c = cvWaitKey(3);
if((char)c == 27) break;
}
std::cerr << "The " << frameNum << "-th frame" << std::endl;
frameNum++;
}
if( show == 1 )
cvDestroyWindow("Video");
return 0;
}
Then I compile it like:
g++ test.cpp -o Video -pipe -D __STDC_CONSTANT_MACROS -D STD=std -Wall -I. -I/usr/local/ -O3 -DNDEBUG -ggdb -L/usr/local/ -lopencv_core -lopencv_highgui -lopencv_video -lopencv_imgproc -lavformat -lavdevice -lavutil -lavcodec -lswscale
Compilation works fine and no errors returned.
However, when I was running it, I got:
(Video:5651): GLib-GObject-CRITICAL **: g_object_set: assertion 'G_IS_OBJECT (object)' failed
Could not initialize capturing..
Some other information:
1. I test my opencv and ffmpeg by running simple examples, which work well.
2. I can stream frames from my camera and display it using opencv.
Anyone has idea of what causes this?
Any idea is appreciated.
I want to:
write a vtkMultiBlockDataSet, containing a vtkStringArray, to a
file
load it
add some more Blocks
write it again to a file
You can get a simplified code from here.
The program produces segfaults, but only if the writers are set to binary mode, and only if the data exceeds a certain size. In ASCII mode, everything is fine.
This might be related.
Can you confirm that behaviour? What am I doing wrong? And if it is a bug, how can I work around?
Thanks very much for any help.
EDIT: I directly add the example code (the same as from the given link above) here:
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkXMLMultiBlockDataWriter.h>
#include <vtkXMLMultiBlockDataReader.h>
#include <vtkStringArray.h>
#include <sys/stat.h>
#include <sstream>
int main(int, char *[])
{
/**
* notes:
* -> it works with ascii writer configuration (BINARY=0) for any M,N.
* -> with binary writer configuration (BINARY=1), it segfaults for higher M,N
* -> {N=100,M=1} works. {N=100,M=10} fails. {N=1000,M=1} fails.
*/
const unsigned int N = 1000; // number of points
const unsigned int M = 1; // number of characters in the string
const bool BINARY = 1; // 0=ascii, 1=binary
std::string filename = "output/test_output.vtm";
std::stringstream mystring;
struct stat buffer;
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkStringArray> stringAttribute =
vtkSmartPointer<vtkStringArray>::New();
vtkSmartPointer<vtkPolyData> mypolydata =
vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkMultiBlockDataSet> multiBDS =
vtkSmartPointer<vtkMultiBlockDataSet>::New ();
vtkSmartPointer<vtkXMLMultiBlockDataWriter> writer1 =
vtkSmartPointer<vtkXMLMultiBlockDataWriter>::New();
vtkSmartPointer<vtkMultiBlockDataSet> multiBDS_read =
vtkSmartPointer<vtkMultiBlockDataSet>::New ();
vtkSmartPointer<vtkXMLMultiBlockDataReader> reader =
vtkSmartPointer<vtkXMLMultiBlockDataReader>::New();
vtkSmartPointer<vtkXMLMultiBlockDataWriter> writer2 =
vtkSmartPointer<vtkXMLMultiBlockDataWriter>::New();
stringAttribute->SetNumberOfComponents(1);
reader->SetFileName(filename.c_str());
writer1->SetFileName(filename.c_str());
writer2->SetFileName(filename.c_str());
if (BINARY) {
writer1->SetDataModeToBinary(); //segfault
writer2->SetDataModeToBinary(); // segfault
}
else {
writer1->SetDataModeToAscii(); // works
writer2->SetDataModeToAscii(); // works
}
//create output folder and clear content:
std::string outfolder = "output/";
mkdir(outfolder.c_str(), 0777);
system("exec rm -r output/*");
// create some points:
for (int k=0; k<N; ++k) {
points->InsertNextPoint(0.0, 0.0, 0.0);
}
// create some string attributes:
for (int k=0; k<N; ++k) {
for (int i=0; i<M; ++i) {
mystring << "x";
}
stringAttribute->InsertNextValue(mystring.str().c_str());
}
// assemble and write to file:
mypolydata->SetPoints(points);
mypolydata->GetPointData()->AddArray(stringAttribute);
multiBDS->SetBlock(0,mypolydata);
writer1->SetInput(multiBDS);
writer1->Write();
//now read the file again:
if (stat (filename.c_str(), &buffer) == 0) {
reader->Update();
multiBDS_read->ShallowCopy(reader->GetOutput());
}
else {
std::cout<<"file not found."<<std::endl;
}
// assemble and write again:
//system("exec rm -r output/*"); // remove original file; not necessary
multiBDS_read->SetBlock(multiBDS->GetNumberOfBlocks(),mypolydata);
writer2->SetInput(multiBDS_read);
writer2->Write();
return EXIT_SUCCESS;
}
If you use cmake, please use the following CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
PROJECT(vtk_weird_segfault)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(vtk_weird_segfault MACOSX_BUNDLE vtk_weird_segfault)
if(VTK_LIBRARIES)
target_link_libraries(vtk_weird_segfault ${VTK_LIBRARIES})
else()
target_link_libraries(vtk_weird_segfault vtkHybrid vtkWidgets)
endif()
In Windows, winapi provides a function that reports information about a monitor:
DEVMODE dm;
dm.dmSize = sizeof(DEVMODE);
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm);
int FPS = dm.dmDisplayFrequency;
What is the equivalent of this on Linux? The Linux man pages direct me to an allegro library function, but not only am I not using allegro, that function is from a very outdated version of said library and reportedly only works on Windows.
Use XRandr API (man 3 Xrandr). See here for an example:
http://www.blitzbasic.com/Community/posts.php?topic=86911
You can also look at the code for xrandr(1).
Edit1: For posterity sake:
Sample code slightly adjusted so its more of a demo:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
int main()
{
int num_sizes;
Rotation current_rotation;
Display *dpy = XOpenDisplay(NULL);
Window root = RootWindow(dpy, 0);
XRRScreenSize *xrrs = XRRSizes(dpy, 0, &num_sizes);
//
// GET CURRENT RESOLUTION AND FREQUENCY
//
XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root);
short current_rate = XRRConfigCurrentRate(conf);
SizeID current_size_id = XRRConfigCurrentConfiguration(conf, ¤t_rotation);
int current_width = xrrs[current_size_id].width;
int current_height = xrrs[current_size_id].height;
std::cout << "current_rate = " << current_rate << std::endl;
std::cout << "current_width = " << current_width << std::endl;
std::cout << "current_height = " << current_height << std::endl;
XCloseDisplay(dpy);
}
Compile with:
g++ 17797636.cpp -o 17797636 -lX11 -lXrandr
Output:
$ ./17797636
current_rate = 50
current_width = 1920
current_height = 1080
A simple example:
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
int main(int argc, char *argv[])
{
Display *display = XOpenDisplay(NULL);
Window default_root_window = XDefaultRootWindow(display);
XRRScreenResources *screen_resources = XRRGetScreenResources(display, default_root_window);
RRMode active_mode_id = 0;
for (int i = 0; i < screen_resources->ncrtc; ++i) {
XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(display, screen_resources, screen_resources->crtcs[i]);
// If None, then is not displaying the screen contents
if (crtc_info->mode != None) {
active_mode_id = crtc_info->mode;
}
}
double active_rate = 0;
for (int i = 0; i < screen_resources->nmode; ++i) {
XRRModeInfo mode_info = screen_resources->modes[i];
if (mode_info.id == active_mode_id) {
active_rate = (double)mode_info.dotClock / ((double)mode_info.hTotal * (double)mode_info.vTotal);
}
}
printf("Active rate is: %.1f\n", active_rate);
return 0;
}
Iwan's answer did not work for me; xrandr has changed since 2013 I guess? The command-line tool xrandr can read my refresh rate correctly, but its source code is too complex for me to be willing to copy the way it's doing so. Instead I have chosen to clumsily delegate the work to the entire xrandr program. My crappy solution is pasted below.
Note that this solution is likely to be unreliable when multiple display devices are connected, and will probably someday break when xrandr changes again.
(pstream.h is provided by Jonathan Wakely's PStreams library, referenced here: https://stackoverflow.com/a/10702464/1364776
I'm only using it to turn the output of a command into a std::string; obviously there are various other ways to do that so use one of them if you prefer.)
#include <pstream.h>
#include <cctype>
#include <cstdlib>
#include <cmath>
float getRefreshRate()
{
try
{
redi::ipstream queryStream("xrandr");
std::string chunk;
while (queryStream >> chunk)
{
auto rateEnd = chunk.find("*");
if (rateEnd != std::string::npos)
{
auto rateBeginning = rateEnd;
while (std::isdigit(chunk[rateBeginning]) || std::ispunct(chunk[rateBeginning]))
--rateBeginning;
++rateBeginning;
auto numberString = chunk.substr(rateBeginning, rateEnd - rateBeginning);
float rate = std::strtof(numberString.data(), nullptr);
if (rate != 0 && rate != HUGE_VALF)
return rate;
}
}
}
catch (...)
{
}
return 60; // I am not proud of any of this :(
}
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