Shobhit Puri
Shobhit Puri

Reputation: 26007

Convert an image loaded using PIL to a Cimg image object

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?

Upvotes: 5

Views: 1695

Answers (2)

Mark Setchell
Mark Setchell

Reputation: 207485

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.sstatic.net/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'

Upvotes: 0

cubuspl42
cubuspl42

Reputation: 8380

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.

Upvotes: 0

Related Questions