Convert an image loaded using PIL to a Cimg image object - c++

I am trying to convert a iamge loaded using PIL to a Cimg image object. I understand that Cimg is a c++ library and PIL is a python imaging library. Given an image url, my aim is to calculate the pHash of an image without writing it onto a disk. pHash module works with a Cimg image object and it has been implemented in C++. So I am planning to send the required image data from my python program to the c++ program using python extension binding. In the following code sniplet, I am loading the image from the given url:
//python code sniplet
import PIL.Image as pil
file = StringIO(urlopen(url).read())
img = pil.open(file).convert("RGB")
The Cimg image object that I need to construct looks as follows:
CImg ( const t *const values,
const unsigned int size_x,
const unsigned int size_y = 1,
const unsigned int size_z = 1,
const unsigned int size_c = 1,
const bool is_shared = false
)
I can get the width(size_x) and height(size_y) using img.size and can pass it to c++. I am unsure of how to fill 'values' field of the Cimg object? What kind of data structure to use to pass the image data from the python to c++ code?
Also, is there any other way to convert a PIL image to Cimg?

I assume that your main application is written in Python and you want to call C++ code from Python. You can achieve that by creating a "Python module" that will expose all native C/C++ functionality to Python. You can use a tool like SWIG to make your work easier.
That's the best solution of your problem that came to my mind.

The simplest way to pass an image from Python to a C++ CImg-based program is via a pipe.
So this a C++ CImg-based program that reads an image from stdin and returns a dummy pHash to the Python caller - just so you can see how it works:
#include "CImg.h"
#include <iostream>
using namespace cimg_library;
using namespace std;
int main()
{
// Load image from stdin in PNM (a.k.a. PPM Portable PixMap) format
cimg_library::CImg<unsigned char> image;
image.load_pnm("-");
// Save as PNG (just for debug) rather than generate pHash
image.save_png("result.png");
// Send dummy result back to Python caller
std::cout << "pHash = 42" << std::endl;
}
And here is a Python program that downloads an image from a URL, converts it into a PNM/PPM ("Portable PixMap") and sends it to the C++ program so it can generate and return a pHash:
#!/usr/bin/env python3
import requests
import subprocess
from PIL import Image
from io import BytesIO
# Grab image and open as PIL Image
url = 'https://i.stack.imgur.com/DRQbq.png'
response = requests.get(url)
img = Image.open(BytesIO(response.content)).convert('RGB')
# Generate in-memory PPM image which CImg can read without any libraries
with BytesIO() as buffer:
img.save(buffer,format="PPM")
data = buffer.getvalue()
# Start CImg passing our PPM image via pipe (not disk)
with subprocess.Popen(["./main"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc:
(stdout, stderr) = proc.communicate(input=data)
print(f"Returned: {stdout}")
If you run the Python program, you get:
Returned: b'pHash = 42\n'

Related

Reading Geospatial Raster files with GDAL and OpenCV3.1.0

I'm trying to implement and run OpenCV sample code Reading Geospatial Raster files with GDAL
For DEM model, i download N37W123.hgt.zip from the SRTM file located at the USGS , (that is in the Results section of that page).
but, DEM model not loaded to cv::Mat dem by cv::Mat dem = cv::imread(argv[2], cv::IMREAD_LOAD_GDAL | cv::IMREAD_ANYDEPTH ); and i get run time error throw std::runtime_error("DEM image type must be CV_16SC1");
1) Why is this happening?
2) All DEM data type are 16 signed integer. is it ok?
3) How can read DEM model block with GDALDataset::RasterIO or GDALRasterBand::ReadBlock directly?
Most Likely you have to enable/set WITH_GDAL flag to true in CMake while building opencv.
for reference:
https://docs.opencv.org/4.4.0/d4/da8/group__imgcodecs.html#imread
gdal is most likely expecting an HGT file, not a ZIP file: Link.
In Python you would extract the archive first using the zipfile module, then you can access the file directly into a numpy array:
from osgeo import gdal
ds = gdal.Open(filename)
data = ds.ReadAsArray()
EDIT: You've pointed out in a comment that you are using C++, so see the tutorial for reading the image directly: Link

How do I load an image (raw bytes) with OpenCV?

I am using Mat input = imread(filename); to read an image but I'd like to do it from memory instead. The source of the file is from an HTTP server. To make it faster, instead of writing the file to disk and then use imread() to read from it, i'd like to skip a step and directly load it from memory. How do I go about doing this?
Updated to add error
I tried the following but I'm getting segmentation fault
char * do_stuff(char img[])
{
vector<char> vec(img, img + strlen(img));
Mat input = imdecode(Mat(vec), 1);
}
See the man page for imdecode().
http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html#imdecode
I had a similar problem. I needed to decode a jpeg image stream in memory and use the Mat image output for further analysis.
The documentation on OpenCV::imdecode did not provide me enough information to solve the problem.
However, the code here by OP worked for me. This is how I used it ( in C++ ):
//Here pImageData is [unsigned char *] that points to a jpeg compressed image buffer;
// ImageDataSize is the size of compressed content in buffer;
// The image here is grayscale;
cv::vector<unsigned char> ImVec(pImageData, pImageData + ImageDataSize);
cv:Mat ImMat;
ImMat = imdecode(ImVec, 1);
To check I saved the ImMat and was able to open the image file using a image viewer.
cv::imwrite("opencvDecodedImage.jpg", ImMat);
I used : OpenCV 2.4.10 binaries for VC10 on x86.
I hope this information can help others.

Find out the page count of a multipage tiff using the CImg Library

Has one of you ever tried to find out the page count of a multi-page TIFF file usign the CImg library?
I'm trying to calculte the histograms for every single page in the file.
This is my code to load the TIFF file and create an Image object:
#define cimg_use_tiff
#include <CImg.h>
using namespace cimg_library;
void reader::read_tiff(char * filename){
CImg<short> img(filename);
}
I could propably try to use the
CImg<T>::load_tiff (const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U, const unsigned int step_frame=1)`
function and check if the returned image is null / an exception is thrown. This does not seem like a clean way to to what I want. Any ideas are appreciated!
Looks like the CImgList::load_tiff() function will be your friend.
A multi-page tiff file may contain several images with different sizes, so
it is better to use a CImgList to get the result, as any image of the list can
have a different size (which is not the case for each z-slice of a CImg).

Python API for C++

I have a code on C++, that creates file and writes data to it. Is it possible to use Python's functions to use Python's functionality in my C++ code? For example, I'd like to do this:
# Content of function.py
from PIL import Image
imgObject = Image.open('myfile.jpg') # Create Image object
pixArray = imgObject.load() # Create array of pixels
pixColor = pixArray[25, 25] # Get color of pixel (25,25)
I want to write pixColor to text file using C++ possibilities:
#include <fstream>
#include <iostream>
int main()
{
ofstream fout('color.txt', ios_base::out | ios_base::binary);
fout << pixColor;
}
That's only example. My application will really detect color of each pixel and will output it in 'color.txr' file, so I need something faster than Python. Is there a possibility to do it? Thanks a lot!
You may have a look to boost::python library which is really great for interfacing python and C++.

converting a binary stream into a png format

I will try to be clear ....
My project idea is as follow :
I took several compression algorithms which I implemented using C++, after that I took a text file and applied to it the compression algorithms which I implemented, then applied several encryption algorithms on the compressed files, now I am left with final step which is converting these encrypted files to any format of image ( am thinking about png since its the clearest one ).
MY QUESTION IS :
How could I transform a binary stream into a png format ?
I know the image will look rubbish.
I want the binary stream to be converted to a an png format so I can view it as an image
I am using C++, hope some one out there can help me
( my previous thread which was closed )
https://stackoverflow.com/questions/5773638/converting-a-text-file-to-any-format-of-images-png-etc-c
thanx in advance
Help19
If you really really must store your data inside a PNG, it's better to use a 3rd party library like OpenCV to do the work for you. OpenCV will let you store your data and save it on the disk as PNG or any other format that it supports.
The code to do this would look something like this:
#include <cv.h>
#include <highgui.h>
IplImage* out_image = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, bits_pr_pixel);
char* buff = new char[width * height * bpp];
// then copy your data to this buff
out_image->imageData = buff;
if (!cvSaveImage("fake_picture.png", out_image))
{
std::cout << "ERROR: Failed cvSaveImage" << std::endl;
}
cvReleaseImage(&out_image);
The code above it's just to give you an idea on how to do what you need using OpenCV.
I think you're better served with a bi-dimensional bar code instead of converting your blob of data into a png image.
One of the codes that you could use is the QR code.
To do what you have in mind (storing data in an image), you'll need a lossless image format. PNG is a good choice for this. libpng is the official PNG encoding library. It's written in C, so you should be able to easily interface it with your C++ code. The homepage I linked you to contains links to both the source code so you can compile libpng into your project as well as a manual on how to use it. A few quick notes on using libpng:
It uses setjmp and longjmp for error handling. It's a little weird if you haven't worked with C's long jump functionality before, but the manual provides a few good examples.
It uses zlib for compression, so you'll also have to compile that into your project.