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
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
.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.
.c
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule",
"Python3 C API Module",
-1,
myMethods
};
Écrivez le nom et la description du 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.
.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.
setup.py
from distutils.core import setup, Extension
setup(name = 'mymodule', version = '1.0.0', ext_modules = [Extension('mymodule', ['mymodule.c'])])
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
main.py
import mymodule
mymodule.helloworld()
Exécutez le programme Python et les fichiers du module .so
dans le même répertoire.
$ python3 main.py
Hello, world
À 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.
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 ) **.
Recommended Posts