I made a module in C language to filter images loaded by Python

At work, I had to do image processing using Python. If it is within the range that can be done with OpenCV etc., that is fine, but the filter of the original algorithm does not have a practical speed unless it is C / C ++. So, I made a module for Python in C language.

If you want to try it out quickly, please use my repository. https://github.com/soramimi/pymodule-image-filter

How to make your own module for Python

Installation of dependent modules

The first trial is hello world, so it is unnecessary, but since numpy, pillow, and matplotlib are used in the later image processing section, these modules need to be installed. It is supposed to be developed on Ubuntu. You need a Python development package.

sudo apt install python3-dev python3-matplotlib

Write a function definition structure

.c


static PyMethodDef myMethods[] = {
	{ "helloworld", helloworld, METH_NOARGS, "My helloworld function." },
	{ NULL }
};

The contents of the definition are described in the order of {(function name), (pointer to function), (argument passing method), (description)}.

METH_NOARGS is for functions with no arguments. Use METH_VARARGS to use the argument.

Write a module definition structure

.c


static struct PyModuleDef mymodule = {
	PyModuleDef_HEAD_INIT,
	"mymodule",
	"Python3 C API Module",
	-1,
	myMethods
};

Write the module name and description.

Write a function that initializes the module

.c


PyMODINIT_FUNC PyInit_mymodule(void)
{
	import_array();
	return PyModule_Create(&mymodule);
}

Write the function call ʻimport_array () as needed. This is necessary because this theme deals with arrays in image processing. Not needed if you don't use arrays. You need to run ʻimport_array () in all source code that uses the array API.

Write the function body

.c


static PyObject *helloworld(PyObject *self, PyObject *args)
{
	fprintf(stderr, "Hello, world\n");
	return Py_None;
}

It's the first trial function, so it's hello world. Later, we will implement the code that performs image processing.

Write a build script

setup.py


from distutils.core import setup, Extension
setup(name = 'mymodule', version = '1.0.0', ext_modules = [Extension('mymodule', ['mymodule.c'])])

Build

python3 setup.py build_ext -i

If you have a .so file with a long name, you are successful.

$ ls *.so
mymodule.cpython-35m-x86_64-linux-gnu.so

Write a call (Python side) program

main.py


import mymodule

mymodule.helloworld()

Execute

Run the Python program and module .so files in the same directory.

$ python3 main.py 
Hello, world

Make an image processing filter

As an example, let's make a function that applies a sepia-toned filter. The function name has been changed from hello world to sepia.

The program on the Python side is as follows.

main.py


from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import mymodule

im = np.array(Image.open('kamo.jpg'))

im = mymodule.sepia(im)

print(type(im))
print(im.dtype)
print(im.shape)

plt.imshow(im)
plt.show()

It works as follows.

  1. Load the image file
  2. Filter
  3. Display array information
  4. Display the image

The function definition is as follows.

.c


	{ "sepia", sepia, METH_VARARGS, "Sepia tone image filter" },

This is an excerpt from the C language source.

mymodule.c


static PyObject *sepia(PyObject *self, PyObject *args)
{
	PyArrayObject *srcarray;
	if (!PyArg_ParseTuple(args, "O", &srcarray)) {
		fprintf(stderr, "invalid argument\n");
		return Py_None;
	}

The first (but only one) argument is an array. Get it as an object.

The input array is a three-dimensional array of (height) x (width) x (channel), otherwise an error will occur. The number of channels is limited to 3 (RGB).

.c


	if (srcarray->nd != 3) {
		fprintf(stderr, "invalid image\n");
		return Py_None;
	}
	if (srcarray->dimensions[2] != 3) {
		fprintf(stderr, "invalid image\n");
		return Py_None;
	}

Gets the size of the image.

.c


	int h = srcarray->dimensions[0];
	int w = srcarray->dimensions[1];

Allocate an array to store the filtered image.

.c


	npy_intp dims[] = { h, w, 3 };
	PyObject *image = PyArray_SimpleNew(3, dims, NPY_UBYTE);
	if (!image) {
		fprintf(stderr, "failed to allocate array\n");
		return Py_None;
	}

Do not mistake the order of (height) x (width) x (channel).

The object secured as an array can be cast as a pointer to the array structure as it is.

.c


	PyArrayObject *dstarray = (PyArrayObject *)image;

Apply a filter.

.c


	for (int y = 0; y < h; y++) {
		uint8_t const *src = (uint8_t const *)srcarray->data + y * w * 3;
		uint8_t *dst = (uint8_t *)dstarray->data + y * w * 3;
		for (int x = 0; x < w; x++) {
			uint8_t r = src[x * 3 + 0];
			uint8_t g = src[x * 3 + 1];
			uint8_t b = src[x * 3 + 2];
			r = pow(r / 255.0, 0.62) * 205 + 19;
			g = pow(g / 255.0, 1.00) * 182 + 17;
			b = pow(b / 255.0, 1.16) * 156 + 21;
			dst[x * 3 + 0] = r;
			dst[x * 3 + 1] = g;
			dst[x * 3 + 2] = b;
		}
	}

Return the object and finish.

.c


	return image;
}

that's all.

Error handling is omitted. In case the function returns None (Py_None), such as when an invalid image file is received, a practical program should handle the error appropriately.

As I wrote at the beginning, the full source code is ** here ) **.

image.png

Recommended Posts

I made a module in C language to filter images loaded by Python
Try to make a Python module in C language
I tried adding a Python3 module in C
I made a Python module to translate comment outs
I made a package to filter time series with python
I made a payroll program in Python!
I made a class to get the analysis result by MeCab in ndarray with python
I made a program to collect images in tweets that I liked on twitter with Python
I made a web application in Python that converts Markdown to HTML
I made a CLI tool to convert images in each directory to PDF
I made a script in python to convert .md files to Scrapbox format
I made a program to check the size of a file in Python
I want to create a window in Python
To add a module to python put in Julialang
I made a Caesar cryptographic program in Python.
I want to embed a variable in a Python string
I want to easily implement a timeout in python
I made a prime number generation program in Python
I want to write in Python! (2) Let's write a test
I made a script to put a snippet in README.md
I tried to implement a pseudo pachislot in Python
I want to randomly sample a file in Python
I want to work with a robot in python.
I made a prime number generation program in Python 2
I made a python library to do rolling rank
Heapsort made in C language
A module that makes it easier to write Perl-like filter programs in Python fileinput
I made a program to convert images into ASCII art with Python and OpenCV
I can't sleep until I build a server !! (Introduction to Python server made in one day)
I made a python text
I made a simple typing game with tkinter in Python
I tried to implement a one-dimensional cellular automaton in Python
I made a quick feed reader using feedparser in Python
I made a command to generate a table comment in Django
I tried "How to get a method decorated in Python"
I tried to illustrate the time and time in C language
I made a puzzle game (like) with Tkinter in Python
I tried to make a stopwatch using tkinter in python
I want to make input () a nice complement in python
Use a scripting language for a comfortable C ++ life-OpenCV-Port Python to C ++-
I made a script in Python to convert a text file for JSON (for vscode user snippet)
I made a C ++ learning site
Multi-instance module test in C language
To add a C module to MicroPython ...
I made a Line-bot using Python!
How to collect images in Python
ABC166 in Python A ~ C problem
I made a fortune with Python.
Introduction to Protobuf-c (C language ⇔ Python)
Solve ABC036 A ~ C in Python
How to wrap C in Python
Solve ABC037 A ~ C in Python
I made a daemon with Python
I made a library to easily read config files with Python
I wrote a function to load a Git extension script in Python
I tried to implement a misunderstood prisoner's dilemma game in Python
I wrote a script to extract a web page link in Python
Pass a list by reference from Python to C ++ with pybind11
I made a library that adds docstring to a Python stub file.
I made a command to display a colorful calendar in the terminal
I made a garbled generator that encodes favorite sentences from UTF-8 to Shift-JIS (cp932) in Python