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()
Related
It's a real-time capture system, I need to get the latest changes from a file which is occasionally edited(mostly add content) by other applications.
In other words, how can I get content that added in the period when I open it without reopening the file?
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
ifstream tfile("temp.txt",ios::in);
if(!tfile){
cout<<"open failed"<<endl;
return 0;
}
string str;
while(1){
if(tfile.eof())
continue;
getline(tfile,str);
cout<<str<<endl;
}
tfile.close();
}
C++ / C Solution
If you are looking for a c++ solution you can use the following functions that I had created a while back:
#include <iostream>
#include <string>
// For sleep function
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif
using namespace std;
void watchLogs(const char *FILENAME) {
FILE * f;
unsigned size = 0;
f = fopen(FILENAME , "r");
char c;
while (true) {
if (!size) { // will print content of your log file. If you just want the updates you can remove the current content except the first two lines;
fseek(f, 0, SEEK_END);
size =(unsigned long)ftell(f) ;
fseek (f, 0, SEEK_SET);
char buffer[size + 1];
fread ( buffer, 1, size, f );
buffer[size] = '\0';
cout << buffer << "\n";
}
else if ((c = (char)fgetc(f)) >= 0) {
fseek(f, 0, SEEK_END); // reach end of file
int BUFFER_SIZE =(unsigned long)ftell(f) - size; // save the length of the update to your logs
char buffer[BUFFER_SIZE + 1]; // prepare a buffer to print the characters
fseek(f,-BUFFER_SIZE,SEEK_END); // rewind BUFFER_SIZE characters before the EOF
int i = 0;
do {buffer[i++] = (char)fgetc(f);} while(i < BUFFER_SIZE); // copy to buffer
buffer[i] = '\0'; // don't forget to NULL terminate your buffer
cout << buffer << "\n";
size += i; // increment the size of the current file
}
}
sleep(3); // updates are checked every 3 seconds to avoid running the cpu at fullspeed, you could set the new logs to show up every minutes or every seconds, up to you.
fclose(f);
}
And you can test it with:
int main(int argc, char **argv) {
if (argc < 2)
return 1;
const char *FILENAME = argv[1];
watchLogs(FILENAME);
return 0;
}
./a.out mysql_binary.log
I could have used stringstreamer but I like that this version would also work with c files with some minor tweaks (can't use string).
I hope you will find it helpful!
NB: This assume that your file will only grow and that the changes will be appended to the end of your file.
NB2: This program is not segfault proof, you may want to check the return of fopen etc
Inotify
If you use Linux you could also potentially go for inotify:
Download inotify: sudo apt-get install -y inotify-tools
Then create the following script mywatch.sh
while inotifywait -e close_write $1; do ./$1; done
Give permission to execute:
add chmox +x mywatch.sh
and call it with ./watchit.sh mysql_binary.log
I was testing the RapidJSON library earlier today to see if I could parse a document with nested values, and for some reason I couldn't come up with a solution to the errors I was getting. I searched around Google and Stack Overflow for an hour or two and couldn't find a fix. Here is the code along with the errors:
main.cpp:
#include <iostream>
#include <SFML/Graphics.hpp>
#include "rapidjson/document.h"
#include "include.hpp"
int main() {
unsigned int input = 1;
tile output;
output = LoadTile("../locations.json", input);
std::cout << output.x << std::endl;
return 0;
}
load.cpp
#include <iostream>
#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"
#include "include.hpp"
using namespace rapidjson;
tile LoadTile(std::string fileName, unsigned int number) {
FILE* file = fopen(fileName.c_str(), "r");
char buffer[2048];
FileReadStream stream(file, buffer, 2048);
Document doc;
doc.ParseStream(stream);
tile output;
Value& tileNumber = doc[number];
if(!tileNumber.IsObject()) {
output.overflow = true;
output.x = 0;
output.y = 0;
output.type = "\0";
}else{
output.x = tileNumber[0]["x"].GetInt();
output.y = tileNumber[0]["y"].GetInt();
output.type = tileNumber[0]["type"].GetString();
}
return output;
}
include.hpp:
#include <iostream>
#include <SFML/Graphics.hpp>
#include "rapidjson/document.h"
struct tile {
int x;
int y;
std::string type;
bool overflow = false;
};
tile LoadTile(std::string fileName, unsigned int number);
CMakeLists.txt:
cmake_minimum_required(VERSION 2.6)
project(test)
set(EXECUTABLE_NAME "test")
add_executable(${EXECUTABLE_NAME} main.cpp load.cpp include.hpp)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules" ${CMAKE_MODULE_PATH})
install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin})
locations.json:
{
1:[
{"x":32},
{"y":32},
{"type":"water_c"}
]
}
Errors:
test: /home/.../rapidjson/document.h:1547:rapidjson::GenericValue<Encoding, Allocator>::operator[](rapidjson::SizeType) [with Encoding = rapidjson::UTF8<>; Allocator = rapidjson::MemoryPoolAllocator<>; rapidjson::SizeType = unsigned int]: Assertion `IsArray()' failed.
Aborted (core dumped)
I know it's not the JSON formatting, I've tried everything. Unless there's something really wrong with it. I'm running this on Xubuntu 16.10. Thanks to anyone that can help.
Your JSON is invalid. In JSON, keys must be strings, written with double quotes. More details here.
I suggest using JSONLint to validate JSON strings.
The valid JSON looks like this (1 in double quotes):
{
"1": [{
"x": 32
}, {
"y": 32
}, {
"type": "water_c"
}]
}
Pseudo code:
for(int i=0;i<m_iNumOfClass;i++) {
char str[200];
if(iterk doesn't exist)
sprintf(str, "iterk\\HMMtransiMean%d.txt", i);
iter(iterk exist)
mkdir(iterk+1)
sprintf(str, "iterk+1\\HMMtransiMean%d.txt", i);
}
This is pseudo code what i want to do.
I want to create a folder named iterk1 if it doesn't exist. But if it exist, I create a folder named iterk2. and then, create a txt file named HMMtransiMean%d in that folder created just now.
How can i do it? please help me.
If you can use boost::filesystem (as πάντα ῥεῖ advice) then :
#include <string>
#include <fstream>
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
int main()
{
int m_iNumOfClass(2);
path path_template("/tmp"); //Maybe you should use "C:\\tmp" instead
path_template /= "iter";
path directory;
for(int i=0; i<m_iNumOfClass; i++) {
int directory_index = 0;
do
{
directory_index++;
directory = path_template;
directory += std::to_string(directory_index);
} while (!create_directory(directory));
directory /= "HMMtransiMean";
directory += std::to_string(i) + ".txt";
std::string filename(directory.string());
std::ofstream outfile (filename);
outfile.close();
}
return 0;
}
Note: This solution does not require boost...
I assume you're using windows platform (because you use "\\"):
The first useful function to consider is _mkdir (doc).
You can use the non-zero value to determine whether the folder was created.
To create a file you can use fopen (doc)
This works for me on Windows but should work on Linux as well(with a minor include change from direct.h to #include <sys/stat.h>
and #include <sys/types.h> to have mkdir):
#include <iostream>
#include <sstream>
#include <direct.h>
#include <cstdio>
#include <string>
using namespace std;
int main() {
const string pref = "iterk";
string path = pref;
stringstream suffix;
int i=0;
int res = -1;
do{
res = mkdir(path.c_str());
if( res == 0){
path = path + "/HMMtransiMean" + suffix.str() + ".txt";
break;
}
else{
++i;
suffix.str(string());
suffix << i;
path = pref + suffix.str();
}
} while (EEXIST == errno);
FILE * stream;
if( (stream = fopen(path.c_str(), "w+" )) == NULL ) // C4996
printf( "The file was not opened\n" );
else
printf( "The file was opened\n" );
string data = "Hi";
int numwritten = fwrite( data.c_str() , sizeof( char ), data.length() , stream );
printf( "Wrote %d items\n", numwritten );
fclose( stream );
return 0;
}
If you use it on windows only you should probably use the _mkdir function (as I noted before).
I'm an absolute noobie at C++ as I've only been familiar with Java programming. What I'm trying to do is to read an Image file (.bmp) into a matrix where I can perform a convolution with a 3x3 matrix (filter) on the matrix to produce a new image file with the convoluted image.
I've looked around google and managed to come up with the following implementation:
Image.h file:
// Image.h
#include <fstream> // for file I/O
using namespace std;
typedef unsigned char unchar; // Easier to understand & code.
class MImage {
public:
MImage(const char* fileName); //Constructor
~MImage(); //Deconstructor
void write(const char* fileName);
void smoothFilter(); //smoothing filer.
private:
ifstream* pInFile;
ofstream* pOutFile;
unchar imageHeaderData[1078]; //.bmp header data with offset 1078.
unchar** imageData;
unchar m_smoothFilter[3][3]; // Smoothing Filter.
unchar** filteredData;
};
Image.cpp file:
// Image.cpp
//
#ifndef _Image_h
#define _Image_h
#define WIDTH 128
#define HEIGHT 128
#include "Image.h"
#include <cmath>
#endif
using namespace std;
typedef unsigned char unchar;
//Constructor
MImage::MImage(const char* fileName){
imageData = new unchar* [HEIGHT]; // create new array size: height of image.
filteredData = new unchar* [HEIGHT];// create new array size: height of image.
for (int i = 0; i < HEIGHT; i++) {
imageData[i] = new unchar [WIDTH]; //create matrix.
filteredData[i] = new unchar [WIDTH]; //create matrix.
}
//image I/O
pInFile = new ifstream;
pInFile->open(fileName, ios::in | ios::binary); // open fileName and read as binary.
pInFile->seekg(0, ios::beg); //pos filter at beginning of image file.
pInFile->read(reinterpret_cast<char*>(imageHeaderData),1078); //read bmp header data into array.
for(int i=0; i<HEIGHT; i++) {
pInFile->read(reinterpret_cast<char*>(imageData[i]),WIDTH);//read row into each array entry.
}
pInFile->close(); //close stream.
char m_smoothFilter[3][3] = {
{1,1,1},
{1,2,1},
{1,1,1}
};
}
MImage::~MImage(){
delete pInFile;
delete pOutFile;
for(int i=0; i<HEIGHT; i++){
delete[] imageData[i];
delete[] filteredData[i];
}
delete[] imageData;
delete[] filteredData;
}
void MImage::write(const char* fileName) {
smoothFilter();
pOutFile = new ofstream;
pOutFile->open(fileName, ios::out | ios::trunc | ios::binary);
pOutFile->write(reinterpret_cast<char*>(imageHeaderData), 1078); //write header data onto output
for(int i = 0; i < HEIGHT; i++){
pOutFile->write(reinterpret_cast<char*>(filteredData[i]),WIDTH); // write new image data.
}
pOutFile->close(); //close stream
}
void MImage::smoothFilter(){
//copy input image into new image
for(int i = 0; i < HEIGHT; i++) {
strcpy(reinterpret_cast<char*>(filteredData[i]), reinterpret_cast<char*>(imageData[i]));
}
int sumOfPixels = 0;
for(int i = 1; i < HEIGHT -1; i++) {
for(int j = 1; j < WIDTH -1; j++) {
sumOfPixels = m_smoothFilter[0][0] * imageData[i+1][j-1] + // top left corner
m_smoothFilter[0][1] * imageData[i+1][j] + // top center
m_smoothFilter[0][2] * imageData[i+1][j+1] + // top right corner
m_smoothFilter[1][0] * imageData[i][j-1] + // center left
m_smoothFilter[1][1] * imageData[i][j] + // center center
m_smoothFilter[1][2] * imageData[i][j+1] + // center right
m_smoothFilter[2][0] * imageData[i-1][j-1] + // bottom left corner
m_smoothFilter[2][1] * imageData[i-1][j] + // bottom center
m_smoothFilter[2][2] * imageData[i-1][j+1]; // bottom right corner
filteredData[i][j] = (sumOfPixels / ( m_smoothFilter[0][0] + m_smoothFilter[0][1] +
m_smoothFilter[0][2] + m_smoothFilter[1][0] +
m_smoothFilter[1][1] + m_smoothFilter[1][2] +
m_smoothFilter[2][0] + m_smoothFilter[2][1] +
m_smoothFilter[2][2]));
}
}
}
Main.cpp file:
//
// Main.cpp
//
#include <iostream>
#include "Image.cpp"
#include <fstream>
using namespace std;
int main() {
MImage img("test.bmp");
img.write("output.bmp");
return 0;
}
When I try to run the following file with:
g++ Main.cpp -o main
./main
I get a segmentation:11 error and not sure what is causing this error!
Note: I have to use a pure C++ implementation so cannot use other libraries.
HELP!
EDIT:
I think the code thats giving me the segmentation error is :
for(int i = 0; i < HEIGHT; i++) {
strcpy(reinterpret_cast<char*>(filteredData[i]), reinterpret_cast<char*>(imageData[i]));
}
But not sure why!
EDIT #3:
Works after replacing above code with :
for(int i= 0; i<HEIGHT; i++) {
strncpy (reinterpret_cast<char*>(filteredData[i]),
reinterpret_cast<char*>(imageData[i]),
sizeof(reinterpret_cast<char*>(filteredData[i])));
}
replaced strcpy() with strncpy() which is much safer apparently and that removed the segmentation fault.
In the main function you include "Image.cpp" and there should be "Image.h" otherwise the compiler would recognize another definition of functions already defined in the header file
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