Get size of an array in C++ 17 using pass by reference - c++17

Is there a way to find the size of an array, using pass by reference. The size function works well inside the main function.
#include <iostream>
#include <iterator>
using namespace std;
int hello(int arr[]){
cout<<arr<<endl;
//cout<<size(arr)<<endl;
}
int main(){
int arr[] = {1,2,3,4,6,7,2};
hello(arr);
cout<<arr<<endl;
cout<<size(arr)<<endl;
}

You are passing array by value so hello function takes as its parameter decayed type - int*.
When you pass array by reference, you need to pass one additional non-type template parameter which is length of array and is deduced, therefore inside hello you don't even use std::size to get array's length, just use N:
template<class T, size_t N>
int hello(T (&arr)[N])
{
cout<< size(arr) <<endl; // 7
cout << N << endl; // 7
return 0;
}

Once you pass an array to a function, it becomes a pointer, and there is no way to get the size from that (it will always report 4 or 8 bytes - the size of a pointer value!).
If you need to process an array in a func, you will need to pass in the size as an argument to the function.
#include <iostream>
#include <iterator>
using namespace std;
int hello(int arr[], size_t count)
{
for(size_t i = 0; i < count; ++i)
{
std::cout << arr[i] << std::endl;
}
}
int main(){
int arr[] = {1,2,3,4,6,7,2};
hello(arr, sizeof(arr) / sizeof(int));
return 0;
}
The better alternative in C++, is to use std::vector instead. (which will store the size as a member variable)
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
void hello(const std::vector<int>& arr)
{
for(size_t i = 0; i < arr.size(); ++i)
{
std::cout << arr[i] << std::endl;
}
}
int main(){
std::vector<int> arr = {1,2,3,4,6,7,2};
hello(arr);
return 0;
}

Related

OpenCV / HighGUI draws new windows for each attached object

I'm working through Learning OpenCV 3 by Kaehler & Bradski.
I've applied all errata fixes to this code per http://www.oreilly.com/catalog/errata.csp?isbn=0636920044765.
Expected behavior: the trackbar should be attached to the namedWindow "Example2-4", then frames from a video file (specified via command-line argument) should be drawn in the same window.
Actual behavior: the trackbar is drawn in one window named "Example2-4", then the frames are drawn in a second window named "Example2-4". Closing either window causes the program to hang. Otherwise the behavior is correct.
Platform: Windows 10, x64, OpenCV 3.3
Edit 1:
I tried adding a string literal to the top of main():
char *window_name = "Window";
and replacing every instance of "Example2-4" with window_name. This didn't change the behavior.
Edit 2:
This code is the first time I've tried to add an interactive widget, but adding images and video frames to windows in previous examples also generated two windows with the same name. I suspect I'm up against a configuration issue, but I still have no idea how to solve it.
Edit 3: I've added code for the simplest program that will demonstrate the problem behavior, and changed the title of this post to characterize it better.
Code:
/* Windows precompiled headers */
//#include "stdafx.h"
/* C++ */
#include <iostream>
#include <fstream>
/* OpenCv */
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
int g_slider_position = 0;
int g_run = 1, g_dontset = 0; // start out in single step mode
cv::VideoCapture g_cap;
void onTrackBarSlide(int pos, void *);
int main(int argc, char **argv)
{
cv::namedWindow("Example2-4", CV_WINDOW_AUTOSIZE);
g_cap.open(string(argv[1]));
int frames = (int)g_cap.get(CV_CAP_PROP_FRAME_COUNT);
int tmpw = (int)g_cap.get(CV_CAP_PROP_FRAME_WIDTH);
int tmph = (int)g_cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "Video has " << frames << " frames of dimensions ("
<< tmpw << ", " << tmph << ")." << endl;
cv::createTrackbar("Position", "Example2-4", &g_slider_position, frames,
onTrackBarSlide);
cv::Mat frame;
for (;;) {
if (g_run != 0) {
g_cap >> frame;
if (frame.empty())
break;
int current_pos = (int)g_cap.get(CV_CAP_PROP_POS_FRAMES);
g_dontset = 1;
cv::setTrackbarPos("Position", "Example2-4", current_pos);
cv::imshow("Example2-4", frame);
g_run -= 1;
}
char c = (char)cv::waitKey(10);
if (c == 's') { // single step
g_run = 1;
cout << "Single step, run = " << g_run << endl;
}
if (c == 'r') { // run mode
g_run = -1;
cout << "Run mode, run = " << g_run << endl;
}
if (c == 27)
break;
}
return 0;
}
void onTrackBarSlide(int pos, void *) {
g_cap.set(CV_CAP_PROP_POS_FRAMES, pos);
if (!g_dontset)
g_run = 1;
g_dontset = 0;
}
Simplest code which results in problem behavior. Gets an image via command line argument:
#include <opencv2\opencv.hpp>
int main(int argc, char **argv)
{
char *window_name = "Window";
cv::Mat img = cv::imread(argv[1], -1);
if (img.empty())
return -1;
cv::namedWindow(window_name, CV_WINDOW_AUTOSIZE);
cv::imshow(window_name, img);
cv::waitKey(0);
cv::destroyWindow(window_name);
return 0;
}

How can I store a big matrix within the .cc file?

I am currently working on a Computer Vision / Machine Learning project for university. Sadly, they only allow us to upload one single file and restrict the computation time too much. Hence I need to compute the matrices on my machine and store them in the same file as the code (22500 rows, 1 col and 100 rows + 22500 col and 100 rows + 1 col). I already found a way to export the data (link), but I'm not sure how to initialize the matrix.
What I've tried
#include <opencv/cv.h>
#include <opencv/highgui.h>
int main(int argc, char const *argv[])
{
float data[10] = {1,2,3,4,5,7,8,9,10,11};
cv::Mat A;
// Something is wrong with this line
A = cv::Mat(1, 10, cv::CV_32FC1, data);
return 0;
}
When I compile it, I get:
main.cc: In function ‘int main(int, const char**)’:
main.cc:10:16: error: expected primary-expression before ‘(’ token
A = cv::Mat(1, 10, cv::CV_32FC1, data);
^
In file included from /usr/include/opencv2/core/core_c.h:47:0,
from /usr/include/opencv/cv.h:63,
from main.cc:1:
main.cc:10:28: error: expected unqualified-id before ‘(’ token
A = cv::Mat(1, 10, cv::CV_32FC1, data);
^
Second try
#include <opencv/cv.h>
#include <opencv/highgui.h>
int main(int argc, char const *argv[])
{
float dataHeaderMat1[10] = {1,2,3,4,5,7,8,9,10,11};
cv::Mat matrix1;
// Something is wrong with this line
cv::cvInitMatHeader( &matrix1, 10, 1, CV_64FC1, dataHeaderMat1);
return 0;
}
gives
main.cc:10:5: error: ‘cvInitMatHeader’ is not a member of ‘cv’
cv::cvInitMatHeader( &matrix1, 10, 1, CV_64FC1, dataHeaderMat1);
^
The following works to declare and initialize a matrix:
#include <opencv/cv.h>
#include <opencv/highgui.h>
int main(int argc, char const *argv[])
{
float data[10] = {1,2,3,4,5,7,8,9,10,11};
cv::Mat A;
// Something is wrong with this line
A = cv::Mat(1, 10, CV_32FC1, data);
return 0;
}
However, I'm not too sure if this is the best way for big arrays.
You can try to save image to header file, like this:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
// uncomment for test
//#include "image.h"
int main(int argc, char **argv)
{
// This part creates header file from image.
Mat img=imread("D:\\ImagesForTest\\lena.jpg");
int w=img.cols;
int h=img.rows;
int channels=img.channels();
ofstream os("image.h");
os << "int rows=" << h << ";" << endl;
os << "int cols=" << w << ";" << endl;
os << "unsigned char d[]={" << endl;
for(int i=0;i<h;++i)
{
for(int j=0;j<w;++j)
{
if(i!=(w-1) || j!=(h-1))
{
Vec3b b=img.at<Vec3b>(i,j);
os << format("0x%02x,",b[0]);
os << format("0x%02x,",b[1]);
os << format("0x%02x,",b[2]);
}
}
}
Vec3b b=img.at<Vec3b>(w-1,h-1);
os << format("0x%02x,",b[0]);
os << format("0x%02x,",b[1]);
os << format("0x%02x",b[2]);
os << endl << "};" << endl;
os << "Mat I=Mat(rows,cols,CV_8UC3,d);" << endl;
os.close();
// To test uncomment commented part of code and comment uncommented.
// uncomment for test
/*
namedWindow("I");
imshow("I",I);
waitKey();
return 0;
*/
}
But be careful, not all IDEs likes such large files.

Reading a file in chunks and appending the incomplete line to the next read

I am trying to read in from the following file:
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
12345abcdefghijklmnopqrstu
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
The code is below:
#include <iostream>
#include <fstream>
#include <sstream>
#include <thread>
#include <mutex>
#include <vector>
#include <array>
#include <algorithm>
#include <iterator>
#define CHUNK_SIZE 55
std::mutex queueDumpMutex;
void getLinesFromChunk(std::vector<char>& chunk, std::vector<std::string>& container)
{
static std::string str;
unsigned int i = 0;
while(i < chunk.size())
{
str.clear();
size_t chunk_sz = chunk.size();
while(chunk[i] != '\n' && i < chunk_sz )
{
str.push_back(chunk[i++]);
}
std::cout<<"\nStr = "<<str;
if (i < chunk_sz)
{
std::lock_guard<std::mutex> lock(queueDumpMutex);
container.push_back(str);
}
++i;
}
chunk.clear();
std::copy(str.begin(), str.end(), std::back_inserter(chunk));
std::cout << "\nPrinting the chunk out ....." << std::endl;
std::copy(chunk.begin(), chunk.end(), std::ostream_iterator<char>(std::cout, " "));
}
void ReadFileAndPopulateDump(std::ifstream& in)
{
std::vector<char> chunk;
chunk.reserve(CHUNK_SIZE*2);
std::vector<std::string> queueDump;
in.unsetf(std::ios::skipws);
std::cout << "Chunk capacity: " << chunk.capacity() << std::endl;
do{
in.read(&chunk[chunk.size()], CHUNK_SIZE);
std::cout << "Chunk size before getLines: " << chunk.size() << std::endl;
getLinesFromChunk(chunk, queueDump);
std::cout << "Chunk size after getLines: " << chunk.size() << std::endl;
}while(!in.eof());
}
int main()
{
std::ifstream in("/home/ankit/codes/more_practice/sample.txt", std::ifstream::binary);
ReadFileAndPopulateDump(in);
return 0;
}
What i wish to achieve is for the container to be line complete.
By this i mean that suppose my CHUNK_SIZE reads only:
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
12
The container should look like:
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
instead of:
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz12
Now i understand that chunk.reserve(CHUNK_SIZE) reserves the given memory and does not actually assign a SIZE. Because if this i am not able to read from in.read().
If i use chunk.resize(CHUNK_SIZE) and append it to the end as i want the remaining characters '12' to be appended with its complete line.
Now the issue is that the code is being repeated more than it should. According to me the conditions seem fine.
Any help will be much appreciated.
Sorry but I don't understand why do you:
read the file in binary mode and not in text mode
don't use getline()
use a vector<char> instead a string
For what I understand the problem you propose, I would do it this way
#include <cstdlib>
#include <fstream>
#include <iostream>
int main()
{
std::ifstream f("sample.txt"); // text mode!
std::size_t const chunkSizeMax = 55U;
std::string str;
std::string chunk;
while ( std::getline(f, str) )
{
if ( chunkSizeMax <= (chunk.size() + str.size()) )
{
std::cout << "chunk: [" << chunk << "]\n";
chunk.clear();
}
chunk += str;
}
std::cout << "last chunk: [" << chunk << "]\n";
return EXIT_SUCCESS;
}
Hoping this helps.

Can you improve this solution to interfacing OpenCV 2.4+ to Zxing 1D barcode reader

I didn't find this solution on the net, had to figure it myself. So, for benefit of others, I'm posing this as a "question":
Can you improve my working interface of OpenCV 2.4+ to the C++ version of Zxing 2.2 1D barcode reader?
Here's my working but perhaps improvable implementation below:
/**
* Gary Bradski, Reading 1D barcodes
* License BSD, (c) 2013
*
* Working example of how to call zxing using OpenCV 2.4+ cv::Mat
*
* Calling example, this one for 128 barcodes:
*
* Code128Reader cr; //Instantiate a zxing barcode reader, int this case for 128 barcodes,
* // but you can use any of their 1D or multi readers here
* ... by magic, I find, rectify and islotate a barcode into cv::Mat barcodeImage
* decode_image(&cr, barcodeImage); //Decode the isolated rectified barcode or fail
*
*/
#include <string>
#include <fstream>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
//////////////ZXING BARCODE READER//////////////////////////////////////////
#include <zxing/LuminanceSource.h>
#include <zxing/MultiFormatReader.h>
#include <zxing/oned/OneDReader.h>
#include <zxing/oned/EAN8Reader.h>
#include <zxing/oned/EAN13Reader.h>
#include <zxing/oned/Code128Reader.h>
#include <zxing/datamatrix/DataMatrixReader.h>
#include <zxing/qrcode/QRCodeReader.h>
#include <zxing/aztec/AztecReader.h>
#include <zxing/common/GlobalHistogramBinarizer.h>
#include <zxing/Exception.h>
using namespace zxing;
using namespace oned;
using namespace datamatrix;
using namespace qrcode;
using namespace aztec;
class OpenCVBitmapSource : public LuminanceSource
{
private:
cv::Mat m_pImage;
public:
OpenCVBitmapSource(cv::Mat &image)
: LuminanceSource(image.cols, image.rows)
{
m_pImage = image.clone();
}
~OpenCVBitmapSource(){}
int getWidth() const { return m_pImage.cols; }
int getHeight() const { return m_pImage.rows; }
ArrayRef<char> getRow(int y, ArrayRef<char> row) const //See Zxing Array.h for ArrayRef def
{
int width_ = getWidth();
if (!row)
row = ArrayRef<char>(width_);
const char *p = m_pImage.ptr<char>(y);
for(int x = 0; x<width_; ++x, ++p)
row[x] = *p;
return row;
}
ArrayRef<char> getMatrix() const
{
int width_ = getWidth();
int height_ = getHeight();
ArrayRef<char> matrix = ArrayRef<char>(width_*height_);
for (int y = 0; y < height_; ++y)
{
const char *p = m_pImage.ptr<char>(y);
int yoffset = y*width_;
for(int x = 0; x < width_; ++x, ++p)
{
matrix[yoffset + x] = *p;
}
}
return matrix;
}
/*
// The following methods are not supported by this demo (the DataMatrix Reader doesn't call these methods)
bool isCropSupported() const { return false; }
Ref<LuminanceSource> crop(int left, int top, int width, int height) {}
bool isRotateSupported() const { return false; }
Ref<LuminanceSource> rotateCounterClockwise() {}
*/
};
void decode_image(Reader *reader, cv::Mat &image)
{
try
{
Ref<OpenCVBitmapSource> source(new OpenCVBitmapSource(image));
Ref<Binarizer> binarizer(new GlobalHistogramBinarizer(source));
Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));
Ref<Result> result(reader->decode(bitmap, DecodeHints(DecodeHints::TRYHARDER_HINT)));//+DecodeHints::DEFAULT_HINT)));
cout << result->getText()->getText() << endl;
//Export the read barcode here
}
catch (zxing::Exception& e)
{
//Export your failure to read the code here
cerr << "Error: " << e.what() << endl;
}
}
Forgot to attribute what I started with. There is an out of date (will not compile) implementation using IplImages here:
http://www.idealsoftware.com/opensource/scan-1d-2d-barcodes-webcam-zxing-opencv-visual-c.html
This updates that solution so that it works with Zxing 2.2 and OpenCV 2.1+
I think you can avoid the matrix copy by replacing
Ref<OpenCVBitmapSource> source(new OpenCVBitmapSource(image));
With
Ref<LuminanceSource> source(new GreyscaleLuminanceSource(image.data, image.step, image.rows, 0, 0, image.cols, image.rows));

Copy select rows into new matrix

I want to copy the rows 0, 2 and 4 of my matrix A into B, in this order.
Let A = [a0, a1, a2, a3, a4]^T , with a_i being row-vectors,
then B should be: [a0, a2, a4]^T.
The code below does what I want but I wonder whether there is a prettier solution (maybe using Eigen)?
#include <iostream>
#include <vector>
#include <opencv/cv.h>
int main(int argc, char **argv) {
const int num_points = 5;
const int vec_length = 3;
cv::Mat A(num_points, vec_length, CV_32FC1);
cv::RNG rng(0); // Fill A with random values
rng.fill(A, cv::RNG::UNIFORM, 0, 1);
// HACK Ugly way to fill that matrix .
cv::Mat B = cv::Mat(3,vec_length, CV_32FC1);
cv::Mat tmp0 = B(cv::Rect(0,0,vec_length,1));
cv::Mat tmp1 = B(cv::Rect(0,1,vec_length,1));
cv::Mat tmp2 = B(cv::Rect(0,2,vec_length,1));
A.row(0).copyTo(tmp0);
A.row(2).copyTo(tmp1);
A.row(4).copyTo(tmp2);
std::cout << "A: " << A << std::endl;
std::cout << "B: " << B << std::endl;
return 0;
}
The way in OpenCV 2.4.1 is:
A.row(0).copyTo(B.row(0));
A.row(2).copyTo(B.row(1));
A.row(4).copyTo(B.row(2));
I found push_back.
Create B with size 0 x vec_length and then use push_back to add the selected rows from A:
#include <iostream>
#include <vector>
#include <opencv/cv.h>
int main(int argc, char **argv) {
const int num_points = 5;
const int vec_length = 3;
cv::Mat A(num_points, vec_length, CV_32FC1);
cv::RNG rng(0); // Fill A with random values
rng.fill(A, cv::RNG::UNIFORM, 0, 1);
cv::Mat B = cv::Mat(0,vec_length, CV_32FC1);
B.push_back(A.row(0));
B.push_back(A.row(2));
B.push_back(A.row(4));
std::cout << "A: " << A << std::endl;
std::cout << "B: " << B << std::endl;
return 0;
}
Since they are non-contiguous I don't think there's any shortcut. In this particular case you could make the code cleaner with a loop:
for (int i=0; i<3; i++) {
cv::Mat tmp = B(cv::Rect(0,i,vec_length,1));
A.row(i * 2).copyTo(tmp);
}
Mat row = old.row(0);
old.row(0).copyTo(row);
new.push_back(row);

Resources