J'ai fait un module en langage C qui filtre les images chargées par Python

Au travail, je devais faire du traitement d'image avec Python. Si c'est dans la plage qui peut être faite avec OpenCV etc., c'est très bien, mais le filtre de l'algorithme d'origine n'a pas de vitesse pratique à moins qu'il ne soit C / C ++. J'ai donc créé un module pour Python en langage C.

Si vous souhaitez l'essayer rapidement, veuillez utiliser mon référentiel. https://github.com/soramimi/pymodule-image-filter

Comment créer votre propre module pour Python

Installation de modules dépendants

Le premier essai est «bonjour le monde», donc ce n'est pas nécessaire, mais comme numpy, oreiller et matplotlib sont utilisés dans la dernière section de traitement d'image, ces modules doivent être installés. Il est censé être développé sur Ubuntu. Nécessite un package de développement Python.

sudo apt install python3-dev python3-matplotlib

Ecrire une structure de définition de fonction

.c


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

Le contenu de la définition est décrit dans l'ordre de {(nom de la fonction), (pointeur vers la fonction), (méthode de passage d'argument), (description)}.

«METH_NOARGS» est pour les fonctions sans arguments. Utilisez METH_VARARGS pour utiliser l'argument.

Ecrire une structure de définition de module

.c


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

Écrivez le nom et la description du module.

Ecrire une fonction qui initialise le module

.c


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

Écrivez l'appel de fonction ʻimport_array () si nécessaire. Cela est nécessaire car ce thème traite des tableaux dans le traitement d'image. Pas nécessaire si vous n'utilisez pas de tableaux. Vous devez exécuter ʻimport_array () dans tout le code source qui utilise l'API du tableau.

Ecrire le corps de la fonction

.c


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

Puisqu'il s'agit de la première fonction d'essai, c'est "bonjour le monde". Plus tard, nous implémenterons le code qui effectue le traitement d'image.

Ecrire un script de construction

setup.py


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

Construire

python3 setup.py build_ext -i

Si vous avez un fichier .so avec un nom long, vous avez réussi.

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

Ecrire un programme d'appel (côté Python)

main.py


import mymodule

mymodule.helloworld()

Exécuter

Exécutez le programme Python et les fichiers du module .so dans le même répertoire.

$ python3 main.py 
Hello, world

Créer un filtre de traitement d'image

À titre d'exemple, utilisons une fonction qui applique un filtre de type sépia. Le nom de la fonction a été changé de «bonjour le monde» à «sépia».

Le programme côté Python est le suivant.

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()

Cela fonctionne comme suit.

  1. Chargez le fichier image
  2. Filtre
  3. Afficher les informations de séquence
  4. Affichez l'image

La définition de la fonction est la suivante.

.c


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

Ceci est un extrait de la source du langage C.

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;
	}

Le premier argument (mais un seul) est un tableau. Obtenez-le comme un objet.

Le tableau d'entrée est un tableau tridimensionnel de (hauteur) x (largeur) x (canal), sinon une erreur se produira. Le nombre de canaux est limité à 3 (RVB).

.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;
	}

Obtenez la taille de l'image.

.c


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

Allouez un tableau pour stocker l'image filtrée.

.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;
	}

Ne vous méprenez pas sur l'ordre de (hauteur) x (largeur) x (canal).

Les objets sécurisés sous forme de tableau peuvent être convertis tels quels en pointeurs vers la structure du tableau.

.c


	PyArrayObject *dstarray = (PyArrayObject *)image;

Appliquez un filtre.

.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;
		}
	}

Renvoyez l'objet et terminez.

.c


	return image;
}

c'est tout.

La gestion des erreurs est omise. Dans le cas où la fonction retourne «Aucun» («Py_None»), par exemple lorsqu'un fichier image non valide est reçu, le programme pratique doit gérer l'erreur de manière appropriée.

Comme je l'ai écrit au début, le code source complet est ** ici ) **.

image.png

Recommended Posts

J'ai fait un module en langage C qui filtre les images chargées par Python
Essayez de créer un module Python en langage C
J'ai essayé d'ajouter un module Python 3 en C
J'ai créé un module Python pour traduire les commentaires
J'ai créé un package pour filtrer les séries chronologiques avec python
J'ai fait un programme de gestion de la paie en Python!
J'ai créé une classe pour obtenir le résultat de l'analyse par MeCab dans ndarray avec python
J'ai créé une application Web en Python qui convertit Markdown en HTML
J'ai créé un outil CLI pour convertir les images de chaque répertoire en PDF
J'ai créé un script en python pour convertir des fichiers .md au format Scrapbox
J'ai fait un programme pour vérifier la taille d'un fichier avec Python
Je veux créer une fenêtre avec Python
Pour ajouter un module à python que vous mettez dans Julialang
J'ai créé un programme cryptographique César en Python.
Je souhaite intégrer une variable dans une chaîne Python
Je veux facilement implémenter le délai d'expiration en python
Je veux écrire en Python! (2) Écrivons un test
J'ai fait un script pour mettre un extrait dans README.md
J'ai essayé d'implémenter un pseudo pachislot en Python
Je veux échantillonner au hasard un fichier avec Python
Je veux travailler avec un robot en python.
J'ai créé une bibliothèque python qui fait rouler le rang
Tri de tas fait en langage C
Fileinput, un module qui facilite l'écriture de programmes de filtrage de type Perl en Python
J'ai créé un programme pour convertir des images en art ASCII avec Python et OpenCV
Je ne peux pas dormir tant que je n'ai pas construit un serveur !! (Introduction au serveur Python faite en un jour)
J'ai fait un texte Python
J'ai fait un jeu de frappe simple avec tkinter de Python
J'ai essayé d'implémenter un automate cellulaire unidimensionnel en Python
J'ai créé un lecteur de flux rapide en utilisant feedparser en Python
J'ai fait une commande pour générer un commentaire pour une table dans Django
J'ai essayé "Comment obtenir une méthode décorée en Python"
J'ai essayé d'illustrer le temps et le temps du langage C
J'ai fait un jeu de puzzle (comme) avec Tkinter of Python
J'ai fait un chronomètre en utilisant tkinter avec python
Je veux ajouter un joli complément à input () en python
Utilisez un langage de script pour une vie C ++ confortable-OpenCV-Port Python vers C ++ -
J'ai créé un script en Python pour convertir un fichier texte pour JSON (pour l'extrait d'utilisateur vscode)
J'ai créé un site d'apprentissage C ++
Test de module multi-instance en langage C
Pour ajouter un module C à MicroPython ...
J'ai fait un Line-bot avec Python!
Comment collecter des images en Python
ABC166 en Python A ~ C problème
J'ai fait une loterie avec Python.
Introduction à Protobuf-c (langage C ⇔ Python)
Résoudre ABC036 A ~ C avec Python
Comment envelopper C en Python
Résoudre ABC037 A ~ C avec Python
J'ai créé un démon avec Python
J'ai créé une bibliothèque qui lit facilement les fichiers de configuration avec Python
J'ai écrit une fonction pour charger le script d'extension Git en Python
J'ai essayé de mettre en œuvre un jeu de dilemme de prisonnier mal compris en Python
J'ai écrit un script pour extraire les liens de pages Web en Python
Passer la liste de Python vers C ++ par référence dans pybind11
J'ai fait une commande pour afficher un calendrier coloré dans le terminal
J'ai créé un générateur brouillé qui encode vos phrases préférées de UTF-8 à Shift-JIS (cp932) en Python