OpenCV Display Pixels Value - c++

I have below code. When I run the program, unknown characters instead of pixel values comes to the screen. I want to display pixel values. How do I do this? Thank you.
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat image = imread("/home/fd/baby.jpg");
for( int i = 0 ; i < image.rows ; i++)
{
for( int j = 0 ; j < image.cols ; j++ )
{
if(image.type() == CV_8UC1)
{
image.at<uchar>(i,j) = 255;
}
else if(image.type() == CV_8UC3)
{
cout << image.at<Vec3b>(i,j)[0] << " " << image.at<Vec3b>(i,j)[1] << " " << image.at<Vec3b>(i,j)[2] << endl;
image.at<Vec3b>(i,j)[0] = 255;
image.at<Vec3b>(i,j)[1] = 255;
image.at<Vec3b>(i,j)[2] = 255;
cout << image.at<Vec3b>(i,j)[0] << " " << image.at<Vec3b>(i,j)[1] << " " << image.at<Vec3b>(i,j)[2] << endl;
}
else
{
cout << "Anknown image format" << endl;
return 0;
}
}
}
imshow("Result İmage", image);
waitKey(0);
}
This is the result screen:

Cast each of the outputs to an integer
<< image.at<Vec3b>(i,j)[0] ...
change to
<< (int)image.at<Vec3b>(i,j)[0] ...
You are printing a char (or probably unsigned char) which is printed through the stream as a single character (which at 255 looks like what you see). Cast to int forces it to display the numerical representation of the value.
The other answers changing the image.at<type> changes how the raw data is interpreted; don't do that. They must be interpreted properly.

Vec3b px= image.at(x,y);
cout << "value: ("<<(int)px.val[0]<<", "<<(int)px.val[1]<<", "<<(int)px.val[2]<<")" << endl;
This works form me.

Change the
image.at<Vec3b>(i, j)
to
image.at<int>(i, j)
or
image.at<double>(i, j)
or
image.at<float>(i, j)
to print the values instead of characters

You are displaying characters try converting using function image.at<int>(j,i);

Related

How to use ONNX model in C++ code on Linux?

I train some Unet-based model in Pytorch. It take an image as an input, and return a mask.
After training i save it to ONNX format, run it with onnxruntime python module and it worked like a charm.
Now, i want to use this model in C++ code in Linux.
Is there simple tutorial (Hello world) when explained:
How to incorporate onnxruntime module to C++ program in Ubuntu
(install shared lib and so on)?
How to properly load an image and pass it to model?
P.S. I found only this: https://www.onnxruntime.ai/docs/tutorials/samples_catalog.html#cc
But there no info about loading image and converting it to ONNX - compatible format in C++ code.
For installation on the Linux, you should refer to https://www.onnxruntime.ai/.
You can refer to the following code to get help regarding how to load and run the ONNX model.
#include <algorithm> // std::generate
#include <assert.h>
#include <iostream>
#include <sstream>
#include <vector>
#include <experimental_onnxruntime_cxx_api.h>
// pretty prints a shape dimension vector
std::string print_shape(const std::vector<int64_t>& v) {
std::stringstream ss("");
for (size_t i = 0; i < v.size() - 1; i++)
ss << v[i] << "x";
ss << v[v.size() - 1];
return ss.str();
}
int calculate_product(const std::vector<int64_t>& v) {
int total = 1;
for (auto& i : v) total *= i;
return total;
}
using namespace std;
int main(int argc, char** argv) {
if (argc != 2) {
cout << "Usage: ./onnx-api-example <onnx_model.onnx>" << endl;
return -1;
}
#ifdef _WIN32
std::string str = argv[1];
std::wstring wide_string = std::wstring(str.begin(), str.end());
std::basic_string<ORTCHAR_T> model_file = std::basic_string<ORTCHAR_T>(wide_string);
#else
std::string model_file = argv[1];
#endif
// onnxruntime setup
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "example-model-explorer");
Ort::SessionOptions session_options;
Ort::Experimental::Session session = Ort::Experimental::Session(env, model_file, session_options); // access experimental components via the Experimental namespace
// print name/shape of inputs
std::vector<std::string> input_names = session.GetInputNames();
std::vector<std::vector<int64_t> > input_shapes = session.GetInputShapes();
cout << "Input Node Name/Shape (" << input_names.size() << "):" << endl;
for (size_t i = 0; i < input_names.size(); i++) {
cout << "\t" << input_names[i] << " : " << print_shape(input_shapes[i]) << endl;
}
// print name/shape of outputs
std::vector<std::string> output_names = session.GetOutputNames();
std::vector<std::vector<int64_t> > output_shapes = session.GetOutputShapes();
cout << "Output Node Name/Shape (" << output_names.size() << "):" << endl;
for (size_t i = 0; i < output_names.size(); i++) {
cout << "\t" << output_names[i] << " : " << print_shape(output_shapes[i]) << endl;
}
// Assume model has 1 input node and 1 output node.
assert(input_names.size() == 1 && output_names.size() == 1);
// Create a single Ort tensor of random numbers
auto input_shape = input_shapes[0];
int total_number_elements = calculate_product(input_shape);
std::vector<float> input_tensor_values(total_number_elements);
std::generate(input_tensor_values.begin(), input_tensor_values.end(), [&] { return rand() % 255; }); // generate random numbers in the range [0, 255]
std::vector<Ort::Value> input_tensors;
input_tensors.push_back(Ort::Experimental::Value::CreateTensor<float>(input_tensor_values.data(), input_tensor_values.size(), input_shape));
// double-check the dimensions of the input tensor
assert(input_tensors[0].IsTensor() &&
input_tensors[0].GetTensorTypeAndShapeInfo().GetShape() == input_shape);
cout << "\ninput_tensor shape: " << print_shape(input_tensors[0].GetTensorTypeAndShapeInfo().GetShape()) << endl;
// pass data through model
cout << "Running model...";
try {
auto output_tensors = session.Run(session.GetInputNames(), input_tensors, session.GetOutputNames());
cout << "done" << endl;
// double-check the dimensions of the output tensors
// NOTE: the number of output tensors is equal to the number of output nodes specifed in the Run() call
assert(output_tensors.size() == session.GetOutputNames().size() &&
output_tensors[0].IsTensor());
cout << "output_tensor_shape: " << print_shape(output_tensors[0].GetTensorTypeAndShapeInfo().GetShape()) << endl;
} catch (const Ort::Exception& exception) {
cout << "ERROR running model inference: " << exception.what() << endl;
exit(-1);
}
}

Reverse a set of points in c++

I need to generate points around a quarter circle in the anticlockwise direction but with my program I'm able to generate in clockwise direction. Below is my code.
#include <iostream>
#include <cmath>
#include <fstream>
#include <iomanip>
using namespace std;
int main ()
{
int NumberPoints(10);
double x1;
const double PI = 3.14159;
double radius = 5;
double angle = 0.7853; //45 degrees
ofstream plot;
string plotDataFile("points.txt");
plot.open(plotDataFile.c_str());
for (int i = 0; i <= NumberPoints; i++)
{
x1 = angle/NumberPoints*i;
plot << setprecision(5) << radius * sin(x1) << " ";
plot << setprecision(5) << radius * cos(x1) << " " << endl;
}
plot.close();
}
I get the following output.
0 5
0.39225 4.9846
0.78208 4.9385
1.1671 4.8619
1.5449 4.7553
1.9132 4.6195
2.2697 4.4552
2.6122 4.2634
2.9386 4.0453
3.2469 3.8023
3.5352 3.5359
I need points in the format
3.5352 3.5359
3.2469 3.8023
2.9386 4.0453
.
.
0 5
Could someone help me modify my code or give me an idea for the same.
How about this?
for (int i = NumberPoints; i >= 0; i--)
{
x1 = angle/NumberPoints*i;
plot << setprecision(5) << radius * sin(x1) << " ";
plot << setprecision(5) << radius * cos(x1) << " " << endl;
}
Instead of
for (int i = 0; i <= NumberPoints; i++)
use
for (int i = NumberPoints; i >= 0; i--)
just iterate backwards:
for (int i = NumberPoints; i >= 0; i--)
By the way, your variable NumberPoints has probably wrong name. Notice that you are getting 11 points, not 10.
may be help
Input:
0 5
0.39225 4.9846
0.78208 4.9385
std::vector< std::pair< std::string, std::string > > pair_of_point;
pair_of_point.emplace_back("0", "5");
pair_of_point.emplace_back("0.39225", "4.9846");
pair_of_point.emplace_back("0.78208", "4.9385");
std::reverse( pair_of_point.begin(), pair_of_point.end()) ;
std::cout << pair_of_point[ 0 ].first << " " << pair_of_point[ 0 ].second << std::endl;
std::cout << pair_of_point[ 1 ].first << " " << pair_of_point[ 1 ].second << std::endl;
std::cout << pair_of_point[ 2 ].first << " " << pair_of_point[ 2 ].second << std::endl;
output
0.78208 4.9385
0.39225 4.9846
0 5
Instead of std::string enter you date-type

Difference in accessing pixel by at and by data OpenCV

Today I observed one interesting thing: if I access image pixel using the function 'at' I received different result then if I access image pixel using image member 'data'.
Does anybody know why it happened?
int main()
{
double sigma = 1.0;
cv::Mat verticalGaussianKernel = getGaussianKernel(7, sigma);
printImg(verticalGaussianKernel);
return 0;
}
void printImg(cv::Mat &img)
{
cout << "---------//------\n";
if (img.empty())
{
cout << "Empty Image\n";
return;
}
for (int i = 0; i < img.size().height; i++)
{
for (int j = 0; j < img.size().width; j++)
{
cout << int(img.data[i * img.size().height + j]) << " " << img.at<double>(i, j) << endl;
}
cout << endl;
}
cout << "---------//------\n";
}
it code gives results:
data-------at
48------0.00443305
63------0.0540056
171-----0.242036
251-----0.39905
10------0.242036
12------0.0540056
84------0.00443305
Firstly I thought that values in data normalizing to 0-255, but the last string refute my guess
Your casting is wrong. The .data member is an uchar*, you're dereferencing it and casting that value (a single uchar) to int thats why you're not getting the correct values.
The proper way to do it would be to cast it to a double* and then dereferencing it. The following code does that.
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
void printImg(cv::Mat &img) {
cout << "---------//------\n";
if (img.empty()) {
cout << "Empty Image\n";
return;
}
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
cout << reinterpret_cast<double *>(img.data)[i * img.cols + j]
<< " " << img.at<double>(i, j) << endl;
}
cout << endl;
}
cout << "---------//------\n";
}
int main() {
double sigma = 1.0;
cv::Mat verticalGaussianKernel = getGaussianKernel(7, sigma);
cout << verticalGaussianKernel << endl;
printImg(verticalGaussianKernel);
return 0;
}
Output:
[0.004433048175243745;
0.05400558262241448;
0.2420362293761143;
0.3990502796524549;
0.2420362293761143;
0.05400558262241448;
0.004433048175243745]
---------//------
0.00443305 0.00443305
0.0540056 0.0540056
0.242036 0.242036
0.39905 0.39905
0.242036 0.242036
0.0540056 0.0540056
0.00443305 0.00443305
You are reading the data as a char . Instead, read it as a double
int main()
{
double sigma = 1.0;
cv::Mat verticalGaussianKernel = getGaussianKernel(7, sigma);
printImg(verticalGaussianKernel);
return 0;
}
void printImg(cv::Mat &img)
{
cout << "---------//------\n";
if (img.empty())
{
cout << "Empty Image\n";
return;
}
for (int i = 0; i < img.size().height; i++)
{
for (int j = 0; j < img.size().width; j++)
{
cout << double(img.data[i * img.size().height*sizeof(double) + j*sizeof(double)]) << " " << img.at<double>(i, j) << endl;
}
cout << endl;
}
cout << "---------//------\n";
}

Histogram Formatting

I am writing a program to create a horizontal histogram from an array of type double data. I was able to get the program to display the boundaries of each sub-interval along with the correct number of asterisks. However, the data is not formatted.
Here's the part of the program responsible for the output:
// endpoints == the boundaries of each sub-interval
// frequency == the number of values which occur in a given sub-interval
for (int i = 0; i < count - 1; i++)
{
cout << setprecision(2) << fixed;
cout << endPoints[i] << " to " << endPoints[i + 1] << ": ";
for (int j = frequency[i]; j > 0; j--)
{
cout << "*";
}
cout << " (" << frequency[i] << ")" << endl;
}
Here's what my output looks like:
0.00 to 3.90: *** (3)
3.90 to 7.80: * (1)
7.80 to 11.70: * (1)
11.70 to 15.60: (0)
15.60 to 19.50: ***** (5)
Here's what I would like it to look like:
00.00 to 04.00: *** (3)
04.00 to 08.00: * (1)
08.00 to 12.00: * (1)
12.00 to 16.00: (0)
16.00 to 20.00: ****** (6)
I've looked up C++ syntax and have found things like setw() and setprecision(). I tried to use both to format my histogram but have not been able to make it look like the model. I was hoping someone could tell me if I'm on the right track and, if so, how to implement setw() and/or setprecision() to properly format my histogram.
Assuming that all numbers are in the [0,100) interval, what you want is a chain of manipulators like:
#include <iostream>
#include <iomanip>
int main() {
std::cout
<< std::setfill('0') << std::setw(5)
<< std::setprecision(2) << std::fixed
<< 2.0
<< std::endl;
return 0;
}
Which will output:
02.00
This is for a single value, you can easily adapt it to suit your needs.
You could, for instance, turn this into an operator and use it like:
#include <iostream>
#include <iomanip>
class FixedDouble {
public:
FixedDouble(double v): value(v) {}
const double value;
}
std::ostream & operator<< (std::ostream & stream, const FixedDouble &number) {
stream
<< std::setfill('0') << std::setw(5)
<< std::setprecision(2) << std::fixed
<< number.value
<< std::endl;
return stream;
}
int main() {
//...
for (int i = 0; i < count - 1; i++) {
std::cout
<< FixedDouble(endPoints[i])
<< " to "
<< FixedDouble(endPoints[i + 1])
<< ": ";
}
for (int j = frequency[i]; j > 0; j--) {
std::cout << "*";
}
std::cout << " (" << frequency[i] << ")" << std::endl;
//...
}

C++ converting binary(P5) image to ascii(P2) image (.pgm)

I am writing a simple program to convert grayscale binary (P5) to grayscale ascii (P2) but am having trouble reading in the binary and converting it to int.
#include <iostream>
#include <fstream>
#include <sstream>
using namespace::std;
int usage(char* arg) {
// exit program
cout << arg << ": Error" << endl;
return -1;
}
int main(int argc, char* argv[]) {
int rows, cols, size, greylevels;
string filetype;
// open stream in binary mode
ifstream istr(argv[1], ios::in | ios::binary);
if(istr.fail()) return usage(argv[1]);
// parse header
istr >> filetype >> rows >> cols >> greylevels;
size = rows * cols;
// check data
cout << "filetype: " << filetype << endl;
cout << "rows: " << rows << endl;
cout << "cols: " << cols << endl;
cout << "greylevels: " << greylevels << endl;
cout << "size: " << size << endl;
// parse data values
int* data = new int[size];
int fail_tracker = 0; // find which pixel failing on
for(int* ptr = data; ptr < data+size; ptr++) {
char t_ch;
// read in binary char
istr.read(&t_ch, sizeof(char));
// convert to integer
int t_data = static_cast<int>(t_ch);
// check if legal pixel
if(t_data < 0 || t_data > greylevels) {
cout << "Failed on pixel: " << fail_tracker << endl;
cout << "Pixel value: " << t_data << endl;
return usage(argv[1]);
}
// if passes add value to data array
*ptr = t_data;
fail_tracker++;
}
// close the stream
istr.close();
// write a new P2 binary ascii image
ofstream ostr("greyscale_ascii_version.pgm");
// write header
ostr << "P2 " << rows << cols << greylevels << endl;
// write data
int line_ctr = 0;
for(int* ptr = data; ptr < data+size; ptr++) {
// print pixel value
ostr << *ptr << " ";
// endl every ~20 pixels for some readability
if(++line_ctr % 20 == 0) ostr << endl;
}
ostr.close();
// clean up
delete [] data;
return 0;
}
sample image - Pulled this from an old post. Removed the comment within the image file as I am not worried about this functionality now.
When compiled with g++ I get output:
$> ./a.out a.pgm
filetype: P5
rows: 1024
cols: 768
greylevels: 255
size: 786432
Failed on pixel: 1
Pixel value: -110
a.pgm: Error
The image is a little duck and there's no way the pixel value can be -110...where am I going wrong?
Thanks.
greylevels: 255
-110 is 146 as an unsigned char. It appears you are on a platform where char is a signed type, try using unsigned char.
If you cannot have negative values , use an unsigned int * instead of int* for your pixel pointers. This way you won't have values read as signed values
You need a correction in output:
ostr << "P2\n" << rows << " "<< cols << " "<< greylevels << endl;