Bei der Arbeit musste ich die Bildverarbeitung mit Python durchführen. Wenn es innerhalb des Bereichs liegt, der mit OpenCV usw. durchgeführt werden kann, ist das in Ordnung, aber der Filter des ursprünglichen Algorithmus hat keine praktische Geschwindigkeit, es sei denn, es ist C / C ++. Also habe ich ein Modul für Python in C-Sprache erstellt.
Wenn Sie es schnell ausprobieren möchten, verwenden Sie bitte mein Repository. https://github.com/soramimi/pymodule-image-filter
Der erste Versuch ist "Hallo Welt", daher ist dies nicht erforderlich. Da in der späteren Bildverarbeitungsversion jedoch Numpy, Pillow und Matplotlib verwendet werden, müssen diese Module installiert werden. Es soll unter Ubuntu entwickelt werden. Benötigt ein Python-Entwicklungspaket.
sudo apt install python3-dev python3-matplotlib
.c
static PyMethodDef myMethods[] = {
{ "helloworld", helloworld, METH_NOARGS, "My helloworld function." },
{ NULL }
};
Der Inhalt der Definition wird in der Reihenfolge {(Funktionsname), (Zeiger auf Funktion), (Argumentübergabemethode), (Beschreibung)} beschrieben.
METH_NOARGS
ist für Funktionen ohne Argumente. Verwenden Sie "METH_VARARGS", um das Argument zu verwenden.
.c
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule",
"Python3 C API Module",
-1,
myMethods
};
Schreiben Sie den Modulnamen und die Beschreibung.
.c
PyMODINIT_FUNC PyInit_mymodule(void)
{
import_array();
return PyModule_Create(&mymodule);
}
Schreiben Sie den Funktionsaufruf import_array ()
nach Bedarf. Dies ist erforderlich, da sich dieses Thema mit Arrays in der Bildverarbeitung befasst. Wird nicht benötigt, wenn Sie keine Arrays verwenden. Sie müssen "import_array ()" für den gesamten Quellcode ausführen, der die Array-API verwendet.
.c
static PyObject *helloworld(PyObject *self, PyObject *args)
{
fprintf(stderr, "Hello, world\n");
return Py_None;
}
Da es die erste Testfunktion ist, ist es "Hallo Welt". Später werden wir den Code implementieren, der die Bildverarbeitung durchführt.
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
Wenn Sie eine .so-Datei mit einem langen Namen haben, sind Sie erfolgreich.
$ ls *.so
mymodule.cpython-35m-x86_64-linux-gnu.so
main.py
import mymodule
mymodule.helloworld()
Führen Sie die Python-Programm- und Moduldateien ".so" im selben Verzeichnis aus.
$ python3 main.py
Hello, world
Verwenden wir als Beispiel eine Funktion, die einen Sepia-ähnlichen Filter anwendet. Der Funktionsname wurde von "Hallo Welt" in "Sepia" geändert.
Das Programm auf der Python-Seite ist wie folgt.
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()
Es funktioniert wie folgt.
Die Funktionsdefinition lautet wie folgt.
.c
{ "sepia", sepia, METH_VARARGS, "Sepia tone image filter" },
Dies ist ein Auszug aus der C-Sprachquelle.
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;
}
Das erste (aber nur ein) Argument ist ein Array. Holen Sie es sich als Objekt.
Das Eingabearray ist ein dreidimensionales Array von (Höhe) x (Breite) x (Kanal), andernfalls tritt ein Fehler auf. Die Anzahl der Kanäle ist auf 3 (RGB) begrenzt.
.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;
}
Holen Sie sich die Größe des Bildes.
.c
int h = srcarray->dimensions[0];
int w = srcarray->dimensions[1];
Ordnen Sie ein Array zum Speichern des gefilterten Bildes zu.
.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;
}
Verwechseln Sie nicht die Reihenfolge (Höhe) x (Breite) x (Kanal).
Als Array gesicherte Objekte können so umgewandelt werden, wie sie sind, um auf Zeiger auf die Array-Struktur zu verweisen.
.c
PyArrayObject *dstarray = (PyArrayObject *)image;
Wenden Sie einen Filter an.
.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;
}
}
Geben Sie das Objekt zurück und beenden Sie den Vorgang.
.c
return image;
}
das ist alles.
Fehlerbehandlung entfällt. Wenn die Funktion "None" ("Py_None") zurückgibt, z. B. wenn eine ungültige Bilddatei empfangen wird, sollte das praktische Programm den Fehler entsprechend behandeln.
Wie ich am Anfang schrieb, ist der vollständige Quellcode ** hier ) **.
Recommended Posts