00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <rc_genicam_api/system.h>
00037 #include <rc_genicam_api/interface.h>
00038 #include <rc_genicam_api/device.h>
00039 #include <rc_genicam_api/stream.h>
00040 #include <rc_genicam_api/buffer.h>
00041 #include <rc_genicam_api/image.h>
00042 #include <rc_genicam_api/config.h>
00043
00044 #include <rc_genicam_api/pixel_formats.h>
00045
00046 #include <Base/GCException.h>
00047
00048 #include <signal.h>
00049
00050 #include <iostream>
00051 #include <fstream>
00052 #include <iomanip>
00053 #include <algorithm>
00054 #include <atomic>
00055 #include <thread>
00056 #include <chrono>
00057
00058 #ifdef _WIN32
00059 #undef min
00060 #undef max
00061 #endif
00062
00063 namespace
00064 {
00065
00071 std::string ensureNewName(std::string name)
00072 {
00073
00074
00075 std::ifstream file(name);
00076
00077 if (file.is_open())
00078 {
00079 file.close();
00080
00081
00082
00083 std::string suffix;
00084
00085 size_t i=name.rfind('.');
00086 if (i != name.npos && name.size()-i <= 4)
00087 {
00088 suffix=name.substr(i);
00089 name=name.substr(0, i);
00090 }
00091
00092
00093
00094 int n=1;
00095 while (n < 100)
00096 {
00097 std::ostringstream s;
00098 s << name << "_" << n << suffix;
00099
00100 file.open(s.str());
00101 if (!file.is_open())
00102 {
00103 name=s.str();
00104 break;
00105 }
00106
00107 file.close();
00108 n++;
00109 }
00110 }
00111
00112 return name;
00113 }
00114
00119 std::string storeBuffer(const std::shared_ptr<GenApi::CNodeMapRef> &nodemap,
00120 const std::shared_ptr<GenApi::CChunkAdapter> &chunkadapter,
00121 const std::string &component, const rcg::Buffer *buffer, uint32_t part)
00122 {
00123
00124
00125 std::ostringstream name;
00126
00127 uint64_t t_sec = buffer->getTimestampNS()/1000000000;
00128 uint64_t t_nsec = buffer->getTimestampNS()%1000000000;
00129
00130 name << "image_" << t_sec << "." << std::setfill('0') << std::setw(9) << t_nsec;
00131
00132 if (component.size() > 0)
00133 {
00134 name << '_' << component;
00135 }
00136
00137 if (chunkadapter)
00138 {
00139
00140 std::int64_t line_status=rcg::getInteger(nodemap, "ChunkLineStatusAll");
00141 bool out1 = line_status & 0x01;
00142 bool out2 = line_status & 0x02;
00143 name << "_" << std::noboolalpha << out1 << "_" << out2;
00144 }
00145
00146
00147
00148 if (!buffer->getIsIncomplete() && buffer->getImagePresent(part))
00149 {
00150 size_t width=buffer->getWidth(part);
00151 size_t height=buffer->getHeight(part);
00152 const unsigned char *p=static_cast<const unsigned char *>(buffer->getBase(part));
00153
00154 size_t px=buffer->getXPadding(part);
00155
00156 uint64_t format=buffer->getPixelFormat(part);
00157 switch (format)
00158 {
00159 case Mono8:
00160 case Confidence8:
00161 case Error8:
00162 {
00163 name << ".pgm";
00164 std::ofstream out(ensureNewName(name.str()), std::ios::binary);
00165
00166 out << "P5" << std::endl;
00167 out << width << " " << height << std::endl;
00168 out << 255 << "\n";
00169
00170 std::streambuf *sb=out.rdbuf();
00171
00172 for (size_t k=0; k<height && out.good(); k++)
00173 {
00174 for (size_t i=0; i<width; i++)
00175 {
00176 sb->sputc(static_cast<char>(*p++));
00177 }
00178
00179 p+=px;
00180 }
00181
00182 out.close();
00183 }
00184 break;
00185
00186 case Coord3D_C16:
00187 {
00188 name << ".pgm";
00189 std::ofstream out(ensureNewName(name.str()), std::ios::binary);
00190
00191 out << "P5" << std::endl;
00192 out << width << " " << height << std::endl;
00193 out << 65535 << "\n";
00194
00195 std::streambuf *sb=out.rdbuf();
00196
00197
00198
00199 if (buffer->isBigEndian())
00200 {
00201 for (size_t k=0; k<height && out.good(); k++)
00202 {
00203 for (size_t i=0; i<width; i++)
00204 {
00205 sb->sputc(static_cast<char>(*p++));
00206 sb->sputc(static_cast<char>(*p++));
00207 }
00208
00209 p+=px;
00210 }
00211 }
00212 else
00213 {
00214 for (size_t k=0; k<height && out.good(); k++)
00215 {
00216 for (size_t i=0; i<width; i++)
00217 {
00218 sb->sputc(static_cast<char>(p[1]));
00219 sb->sputc(static_cast<char>(p[0]));
00220 p+=2;
00221 }
00222
00223 p+=px;
00224 }
00225 }
00226
00227 out.close();
00228 }
00229 break;
00230
00231 case YCbCr411_8:
00232 {
00233 name << ".ppm";
00234 std::ofstream out(ensureNewName(name.str()), std::ios::binary);
00235
00236 out << "P6" << std::endl;
00237 out << width << " " << height << std::endl;
00238 out << 255 << "\n";
00239
00240 std::streambuf *sb=out.rdbuf();
00241
00242 size_t pstep=(width>>2)*6+px;
00243 for (size_t k=0; k<height && out.good(); k++)
00244 {
00245 for (size_t i=0; i<width; i+=4)
00246 {
00247 uint8_t rgb[12];
00248 rcg::convYCbCr411toQuadRGB(rgb, p, static_cast<int>(i));
00249
00250 for (int j=0; j<12; j++)
00251 {
00252 sb->sputc(static_cast<char>(rgb[j]));
00253 }
00254 }
00255
00256 p+=pstep;
00257 }
00258
00259 out.close();
00260 }
00261 break;
00262
00263 default:
00264 std::cerr << "storeBuffer(): Unknown pixel format: "
00265 << GetPixelFormatName(static_cast<PfncFormat>(buffer->getPixelFormat(part)))
00266 << std::endl;
00267 return std::string();
00268 break;
00269 }
00270 }
00271 else if (buffer->getIsIncomplete())
00272 {
00273 std::cerr << "storeBuffer(): Received incomplete buffer" << std::endl;
00274 return std::string();
00275 }
00276 else if (!buffer->getImagePresent(part))
00277 {
00278 std::cerr << "storeBuffer(): Received buffer without image" << std::endl;
00279 return std::string();
00280 }
00281
00282 return name.str();
00283 }
00284
00293 std::string storeBufferAsDisparity(const std::shared_ptr<GenApi::CNodeMapRef> &nodemap,
00294 const std::shared_ptr<GenApi::CChunkAdapter> &chunkadapter,
00295 const rcg::Buffer *buffer, uint32_t part)
00296 {
00297 std::string dispname;
00298
00299 if (!buffer->getIsIncomplete() && buffer->getImagePresent(part) &&
00300 buffer->getPixelFormat(part) == Coord3D_C16 && chunkadapter)
00301 {
00302
00303
00304 int inv=-1;
00305
00306 rcg::setString(nodemap, "ChunkComponentSelector", "Disparity");
00307
00308 if (rcg::getBoolean(nodemap, "ChunkScan3dInvalidDataFlag"))
00309 {
00310 inv=static_cast<int>(rcg::getFloat(nodemap, "ChunkScan3dInvalidDataValue"));
00311 }
00312
00313 double scale=rcg::getFloat(nodemap, "ChunkScan3dCoordinateScale");
00314 double offset=rcg::getFloat(nodemap, "ChunkScan3dCoordinateOffset");
00315 double f=rcg::getFloat(nodemap, "ChunkScan3dFocalLength");
00316 double t=rcg::getFloat(nodemap, "ChunkScan3dBaseline");
00317 double u=rcg::getFloat(nodemap, "ChunkScan3dPrincipalPointU");
00318 double v=rcg::getFloat(nodemap, "ChunkScan3dPrincipalPointV");
00319
00320
00321
00322 if (scale > 0 && f > 0 && t > 0)
00323 {
00324
00325
00326 std::ostringstream name;
00327
00328 uint64_t t_sec = buffer->getTimestampNS()/1000000000;
00329 uint64_t t_nsec = buffer->getTimestampNS()%1000000000;
00330
00331 name << "image_" << t_sec << "." << std::setfill('0') << std::setw(9) << t_nsec;
00332
00333
00334
00335 size_t px=buffer->getXPadding(part);
00336 size_t width=buffer->getWidth(part);
00337 size_t height=buffer->getHeight(part);
00338 const unsigned char *p=static_cast<const unsigned char *>(buffer->getBase(part))+
00339 2*(width+px)*(height+1);
00340
00341 name << "_Disparity";
00342
00343
00344 std::int64_t line_status=rcg::getInteger(nodemap, "ChunkLineStatusAll");
00345 bool out1 = line_status & 0x01;
00346 bool out2 = line_status & 0x02;
00347 name << "_" << std::noboolalpha << out1 << "_" << out2;
00348
00349 dispname=name.str()+".pfm";
00350
00351 std::ofstream out(ensureNewName(dispname), std::ios::binary);
00352
00353 out << "Pf" << std::endl;
00354 out << width << " " << height << std::endl;
00355 out << 1 << "\n";
00356
00357 std::streambuf *sb=out.rdbuf();
00358
00359
00360
00361 bool msbfirst=true;
00362
00363 {
00364 int pp=1;
00365 char *cc=reinterpret_cast<char *>(&pp);
00366 msbfirst=(cc[0] != 1);
00367 }
00368
00369 for (size_t k=0; k<height && out.good(); k++)
00370 {
00371 p-=(width+px)<<2;
00372 for (size_t i=0; i<width; i++)
00373 {
00374 int val;
00375 if (buffer->isBigEndian())
00376 {
00377 val=(static_cast<int>(p[0])<<8)|p[1];
00378 }
00379 else
00380 {
00381 val=(static_cast<int>(p[1])<<8)|p[0];
00382 }
00383
00384 p+=2;
00385
00386 float d=std::numeric_limits<float>::infinity();
00387 if (val != inv)
00388 {
00389 d=static_cast<float>(val*scale+offset);
00390 }
00391
00392 char *c=reinterpret_cast<char *>(&d);
00393
00394 if (msbfirst)
00395 {
00396 sb->sputc(c[0]);
00397 sb->sputc(c[1]);
00398 sb->sputc(c[2]);
00399 sb->sputc(c[3]);
00400 }
00401 else
00402 {
00403 sb->sputc(c[3]);
00404 sb->sputc(c[2]);
00405 sb->sputc(c[1]);
00406 sb->sputc(c[0]);
00407 }
00408
00409 p+=px;
00410 }
00411 }
00412
00413 out.close();
00414
00415
00416
00417
00418 name << "_param.txt";
00419
00420 out.open(ensureNewName(name.str()));
00421
00422 out << "# Created by gc_stream" << std::endl;
00423 out << std::fixed << std::setprecision(5);
00424 out << "camera.A=[" << f << " 0 " << u << "; 0 " << f << " " << v << "; 0 0 1]" << std::endl;
00425 out << "camera.height=" << height << std::endl;
00426 out << "camera.width=" << width << std::endl;
00427 out << "rho=" << f*t << std::endl;
00428 out << "t=" << t << std::endl;
00429
00430 out.close();
00431 }
00432 }
00433
00434 return dispname;
00435 }
00436
00437
00438
00439
00440 std::atomic<bool> user_interrupt(false);
00441
00442 void interruptHandler(int)
00443 {
00444 std::cout << "Stopping ..." << std::endl;
00445
00446 user_interrupt=true;
00447 }
00448
00449 #ifdef _WIN32
00450
00451 void checkUserInterrupt()
00452 {
00453 char a;
00454 std::cin.get(a);
00455
00456 std::cout << "Stopping ..." << std::endl;
00457
00458 user_interrupt=true;
00459 }
00460
00461 #endif
00462
00463 }
00464
00465 int main(int argc, char *argv[])
00466 {
00467 int ret=0;
00468
00469 signal(SIGINT, interruptHandler);
00470
00471 try
00472 {
00473 bool store=true;
00474 int i=1;
00475
00476 if (i < argc)
00477 {
00478 if (std::string(argv[i]) == "-t")
00479 {
00480 store=false;
00481 i++;
00482 }
00483 }
00484
00485 if (i < argc && std::string(argv[i]) != "-h")
00486 {
00487
00488
00489 std::shared_ptr<rcg::Device> dev=rcg::getDevice(argv[i++]);
00490
00491 if (dev)
00492 {
00493 dev->open(rcg::Device::CONTROL);
00494 std::shared_ptr<GenApi::CNodeMapRef> nodemap=dev->getRemoteNodeMap();
00495
00496
00497
00498
00499 std::shared_ptr<GenApi::CChunkAdapter> chunkadapter=rcg::getChunkAdapter(nodemap, dev->getTLType());
00500
00501
00502
00503 int n=1;
00504 while (i < argc)
00505 {
00506
00507
00508 std::string key=argv[i++];
00509 std::string value;
00510
00511 size_t k=key.find('=');
00512 if (k != std::string::npos)
00513 {
00514 value=key.substr(k+1);
00515 key=key.substr(0, k);
00516 }
00517
00518 if (key == "n")
00519 {
00520 n=std::max(1, std::stoi(value));
00521 }
00522 else
00523 {
00524 if (value.size() > 0)
00525 {
00526 rcg::setString(nodemap, key.c_str(), value.c_str(), true);
00527 }
00528 else
00529 {
00530 rcg::callCommand(nodemap, key.c_str(), true);
00531 }
00532 }
00533 }
00534
00535
00536
00537 {
00538 std::vector<std::string> component;
00539
00540 rcg::getEnum(nodemap, "ComponentSelector", component, false);
00541
00542 if (component.size() > 0)
00543 {
00544 std::cout << std::endl;
00545 std::cout << "Available components (1 means enabled, 0 means disabled):" << std::endl;
00546 std::cout << std::endl;
00547
00548 for (size_t k=0; k<component.size(); k++)
00549 {
00550 rcg::setEnum(nodemap, "ComponentSelector", component[k].c_str(), true);
00551
00552 std::cout << component[k] << ": ";
00553 std::cout << rcg::getBoolean(nodemap, "ComponentEnable", true, true);
00554 std::cout << std::endl;
00555 }
00556
00557 std::cout << std::endl;
00558 }
00559 }
00560
00561
00562
00563 std::vector<std::shared_ptr<rcg::Stream> > stream=dev->getStreams();
00564
00565 if (stream.size() > 0)
00566 {
00567 #ifdef _WIN32
00568
00569 std::thread thread_cui(checkUserInterrupt);
00570 thread_cui.detach();
00571 #endif
00572
00573
00574
00575 stream[0]->open();
00576 stream[0]->startStreaming();
00577
00578 std::cout << "Package size: " << rcg::getString(nodemap, "GevSCPSPacketSize") << std::endl;
00579
00580 #ifdef _WIN32
00581 std::cout << "Press 'Enter' to abort grabbing." << std::endl;
00582 #endif
00583 std::cout << std::endl;
00584
00585 int buffers_received=0;
00586 int buffers_incomplete=0;
00587 auto time_start=std::chrono::steady_clock::now();
00588 double latency_ns=0;
00589
00590 for (int k=0; k<n && !user_interrupt; k++)
00591 {
00592
00593
00594 int retry=5;
00595 while (retry > 0 && !user_interrupt)
00596 {
00597 const rcg::Buffer *buffer=stream[0]->grab(3000);
00598
00599 if (buffer != 0)
00600 {
00601 buffers_received++;
00602
00603 if (!buffer->getIsIncomplete())
00604 {
00605
00606
00607 if (chunkadapter)
00608 {
00609 chunkadapter->AttachBuffer(
00610 reinterpret_cast<std::uint8_t *>(buffer->getGlobalBase()),
00611 static_cast<int64_t>(buffer->getSizeFilled()));
00612 }
00613
00614
00615
00616 if (store)
00617 {
00618 uint32_t npart=buffer->getNumberOfParts();
00619 for (uint32_t part=0; part<npart; part++)
00620 {
00621 if (buffer->getImagePresent(part))
00622 {
00623 std::string name;
00624
00625
00626
00627 std::string component=rcg::getComponetOfPart(nodemap, buffer, part);
00628
00629
00630
00631 if (component == "Disparity")
00632 {
00633 name=storeBufferAsDisparity(nodemap, chunkadapter, buffer, part);
00634 }
00635
00636
00637
00638 if (name.size() == 0)
00639 {
00640 name=storeBuffer(nodemap, chunkadapter, component, buffer, part);
00641 }
00642
00643
00644
00645 if (name.size() > 0)
00646 {
00647 std::cout << "Image '" << name << "' stored" << std::endl;
00648 retry=0;
00649 }
00650 }
00651 }
00652 }
00653 else
00654 {
00655
00656
00657 uint64_t t_sec = buffer->getTimestampNS()/1000000000;
00658 uint64_t t_nsec = buffer->getTimestampNS()%1000000000;
00659
00660 std::cout << "Received buffer with timestamp: " << t_sec << "."
00661 << std::setfill('0') << std::setw(9) << t_nsec << std::endl;
00662 retry=0;
00663
00664
00665
00666 auto current=std::chrono::system_clock::now();
00667 latency_ns+=
00668 static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(current.time_since_epoch()).count())-
00669 static_cast<double>(buffer->getTimestampNS());
00670 }
00671
00672
00673
00674 if (chunkadapter) chunkadapter->DetachBuffer();
00675 }
00676 else
00677 {
00678 std::cerr << "Incomplete buffer received" << std::endl;
00679 buffers_incomplete++;
00680 }
00681 }
00682 else
00683 {
00684 std::cerr << "Cannot grab images" << std::endl;
00685 break;
00686 }
00687
00688 retry--;
00689 }
00690 }
00691
00692 stream[0]->stopStreaming();
00693 stream[0]->close();
00694
00695
00696
00697 std::cout << std::endl;
00698 std::cout << "Received buffers: " << buffers_received << std::endl;
00699 std::cout << "Incomplete buffers: " << buffers_incomplete << std::endl;
00700
00701 auto time_stop=std::chrono::steady_clock::now();
00702 std::cout << "Buffers per second: " << std::setprecision(3)
00703 << 1000.0*buffers_received/std::chrono::duration_cast<std::chrono::milliseconds>(time_stop-time_start).count()
00704 << std::endl;
00705
00706 if (!store)
00707 {
00708 if (buffers_received-buffers_incomplete > 0)
00709 {
00710 latency_ns/=buffers_received-buffers_incomplete;
00711 }
00712
00713 std::cout << "Mean latency: " << std::setprecision(5) << latency_ns/1.0e6
00714 << " ms (only meaningful if camera is synchronized e.g. via PTP!)" << std::endl;
00715 }
00716
00717
00718
00719 if (buffers_incomplete == buffers_received)
00720 {
00721 ret=1;
00722 }
00723 }
00724 else
00725 {
00726 std::cerr << "No streams available" << std::endl;
00727 ret=1;
00728 }
00729
00730 dev->close();
00731 }
00732 else
00733 {
00734 std::cerr << "Device '" << argv[1] << "' not found!" << std::endl;
00735 ret=1;
00736 }
00737 }
00738 else
00739 {
00740
00741
00742 std::cout << argv[0] << " -h | [-t] [<interface-id>:]<device-id> [n=<n>] [<key>=<value>] ..." << std::endl;
00743 std::cout << std::endl;
00744 std::cout << "Stores images from the specified device after applying the given optional GenICam parameters." << std::endl;
00745 std::cout << std::endl;
00746 std::cout << "Options:" << std::endl;
00747 std::cout << "-h Prints help information and exits" << std::endl;
00748 std::cout << "-t Testmode, which does not store images and provides extended statistics" << std::endl;
00749 std::cout << std::endl;
00750 std::cout << "Parameters:" << std::endl;
00751 std::cout << "<interface-id> Optional GenICam ID of interface for connecting to the device" << std::endl;
00752 std::cout << "<device-id> GenICam device ID, serial number or user defined name of device" << std::endl;
00753 std::cout << "n=<n> Optional number of images to be received (default is 1)" << std::endl;
00754 std::cout << "<key>=<value> Optional GenICam parameters to be changed in the given order" << std::endl;
00755 #ifdef _WIN32
00756 std::cout << std::endl;
00757 std::cout << "Streaming can be aborted by hitting the 'Enter' key." << std::endl;
00758 #endif
00759 ret=1;
00760 }
00761 }
00762 catch (const std::exception &ex)
00763 {
00764 std::cerr << "Exception: " << ex.what() << std::endl;
00765 ret=2;
00766 }
00767 catch (const GENICAM_NAMESPACE::GenericException &ex)
00768 {
00769 std::cerr << "Exception: " << ex.what() << std::endl;
00770 ret=2;
00771 }
00772 catch (...)
00773 {
00774 std::cerr << "Unknown exception!" << std::endl;
00775 ret=2;
00776 }
00777
00778 rcg::System::clearSystems();
00779
00780 return ret;
00781 }