【Python】Cython使用方法

馋奶兔 提交于 2019-12-15 06:39:52

新建文件_multiotsu.pyx

#cython: cdivision=True
#cython: boundscheck=False
#cython: nonecheck=False
#cython: wraparound=False
import numpy as np

cimport numpy as cnp
cimport cython


def _get_multiotsu_thresh_indices_lut(float [::1] prob,
                                      Py_ssize_t thresh_count):
    cdef Py_ssize_t nbins = prob.shape[0]
    py_thresh_indices = np.empty(thresh_count, dtype=np.intp)
    cdef Py_ssize_t[::1] thresh_indices = py_thresh_indices
    cdef Py_ssize_t[::1] current_indices = np.empty(thresh_count, dtype=np.intp)
    cdef float [::1] var_btwcls = np.zeros((nbins * (nbins + 1)) / 2,
                                           dtype=np.float32)
    cdef float [::1] zeroth_moment = np.empty(nbins, dtype=np.float32)
    cdef float [::1] first_moment = np.empty(nbins, dtype=np.float32)

    with nogil:
        _set_var_btwcls_lut(prob, nbins, var_btwcls, zeroth_moment,
                            first_moment)
        _set_thresh_indices_lut(var_btwcls, hist_idx=0,
                                thresh_idx=0, nbins=nbins,
                                thresh_count=thresh_count, sigma_max=0,
                                current_indices=current_indices,
                                thresh_indices=thresh_indices)

    return py_thresh_indices


cdef void _set_var_btwcls_lut(float [::1] prob,
                              Py_ssize_t nbins,
                              float [::1] var_btwcls,
                              float [::1] zeroth_moment,
                              float [::1] first_moment) nogil:
    cdef cnp.intp_t i, j, idx
    cdef float zeroth_moment_ij, first_moment_ij

    zeroth_moment[0] = prob[0]
    first_moment[0] = prob[0]
    for i in range(1, nbins):
        zeroth_moment[i] = zeroth_moment[i - 1] + prob[i]
        first_moment[i] = first_moment[i - 1] + i * prob[i]
        if zeroth_moment[i] > 0:
            var_btwcls[i] = (first_moment[i]**2) / zeroth_moment[i]

    idx = nbins

    for i in range(1, nbins):
        for j in range(i, nbins):
            zeroth_moment_ij = zeroth_moment[j] - zeroth_moment[i - 1]
            if zeroth_moment_ij > 0:
                first_moment_ij = first_moment[j] - first_moment[i - 1]
                var_btwcls[idx] = (first_moment_ij**2) / zeroth_moment_ij
            idx += 1


cdef float _get_var_btwclas_lut(float [::1] var_btwcls, Py_ssize_t i,
                                Py_ssize_t j, Py_ssize_t nbins) nogil:
    cdef cnp.intp_t idx = (i * (2 * nbins - i + 1)) / 2 + j - i
    return var_btwcls[idx]


cdef float _set_thresh_indices_lut(float[::1] var_btwcls, Py_ssize_t hist_idx,
                                   Py_ssize_t thresh_idx, Py_ssize_t nbins,
                                   Py_ssize_t thresh_count, float sigma_max,
                                   Py_ssize_t[::1] current_indices,
                                   Py_ssize_t[::1] thresh_indices) nogil:
    cdef cnp.intp_t idx
    cdef float sigma

    if thresh_idx < thresh_count:

        for idx in range(hist_idx, nbins - thresh_count + thresh_idx):
            current_indices[thresh_idx] = idx
            sigma_max = _set_thresh_indices_lut(var_btwcls, hist_idx=idx + 1,
                                                thresh_idx=thresh_idx + 1,
                                                nbins=nbins,
                                                thresh_count=thresh_count,
                                                sigma_max=sigma_max,
                                                current_indices=current_indices,
                                                thresh_indices=thresh_indices)

    else:

        sigma = (_get_var_btwclas_lut(var_btwcls, 0, current_indices[0], nbins)
                 + _get_var_btwclas_lut(var_btwcls,
                                        current_indices[thresh_count - 1] + 1,
                                        nbins - 1, nbins))
        for idx in range(thresh_count - 1):
            sigma += _get_var_btwclas_lut(var_btwcls, current_indices[idx] + 1,
                                          current_indices[idx + 1], nbins)

        if sigma > sigma_max:
            sigma_max = sigma
            thresh_indices[:] = current_indices[:]

    return sigma_max


def _get_multiotsu_thresh_indices(float [::1] prob, Py_ssize_t thresh_count):

    cdef Py_ssize_t nbins = prob.shape[0]
    py_thresh_indices = np.empty(thresh_count, dtype=np.intp)
    cdef Py_ssize_t[::1] thresh_indices = py_thresh_indices
    cdef Py_ssize_t[::1] current_indices = np.empty(thresh_count, dtype=np.intp)
    cdef float [::1] zeroth_moment = np.empty(nbins, dtype=np.float32)
    cdef float [::1] first_moment = np.empty(nbins, dtype=np.float32)

    with nogil:
        _set_moments_lut_first_row(prob, nbins, zeroth_moment, first_moment)
        _set_thresh_indices(zeroth_moment, first_moment, hist_idx=0,
                            thresh_idx=0, nbins=nbins,
                            thresh_count=thresh_count, sigma_max=0,
                            current_indices=current_indices,
                            thresh_indices=thresh_indices)

    return py_thresh_indices


cdef void _set_moments_lut_first_row(float [::1] prob,
                                     Py_ssize_t nbins,
                                     float [::1] zeroth_moment,
                                     float [::1] first_moment) nogil:
    cdef cnp.intp_t i

    zeroth_moment[0] = prob[0]
    first_moment[0] = prob[0]
    for i in range(1, nbins):
        zeroth_moment[i] = zeroth_moment[i - 1] + prob[i]
        first_moment[i] = first_moment[i - 1] + i * prob[i]


cdef float _get_var_btwclas(float [::1] zeroth_moment,
                            float [::1] first_moment,
                            Py_ssize_t i, Py_ssize_t j) nogil:

    cdef float zeroth_moment_ij, first_moment_ij

    if i == 0:
        if zeroth_moment[i] > 0:
            return (first_moment[j]**2) / zeroth_moment[j]
    else:
        zeroth_moment_ij = zeroth_moment[j] - zeroth_moment[i - 1]
        if zeroth_moment_ij > 0:
            first_moment_ij = first_moment[j] - first_moment[i - 1]
            return (first_moment_ij**2) / zeroth_moment_ij
    return 0


cdef float _set_thresh_indices(float[::1] zeroth_moment,
                               float[::1] first_moment,
                               Py_ssize_t hist_idx,
                               Py_ssize_t thresh_idx, Py_ssize_t nbins,
                               Py_ssize_t thresh_count, float sigma_max,
                               Py_ssize_t[::1] current_indices,
                               Py_ssize_t[::1] thresh_indices) nogil:
    cdef cnp.intp_t idx
    cdef float sigma

    if thresh_idx < thresh_count:

        for idx in range(hist_idx, nbins - thresh_count + thresh_idx):
            current_indices[thresh_idx] = idx
            sigma_max = _set_thresh_indices(zeroth_moment,
                                            first_moment,
                                            hist_idx=idx + 1,
                                            thresh_idx=thresh_idx + 1,
                                            nbins=nbins,
                                            thresh_count=thresh_count,
                                            sigma_max=sigma_max,
                                            current_indices=current_indices,
                                            thresh_indices=thresh_indices)

    else:

        sigma = (_get_var_btwclas(zeroth_moment, first_moment, 0,
                                  current_indices[0])
                 + _get_var_btwclas(zeroth_moment, first_moment,
                                    current_indices[thresh_count - 1] + 1,
                                    nbins - 1))
        for idx in range(thresh_count - 1):
            sigma += _get_var_btwclas(zeroth_moment, first_moment,
                                      current_indices[idx] + 1,
                                      current_indices[idx + 1])
        if sigma > sigma_max:
            sigma_max = sigma
            thresh_indices[:] = current_indices[:]

    return sigma_max

在同一文件夹下新建setup.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
import numpy as np

# ext_module = cythonize("TestOMP.pyx")    
ext_module = Extension(
    "_multiotsu",
    ["_multiotsu.pyx"],
)

setup(
    cmdclass={'build_ext': build_ext},
    ext_modules=[ext_module],
    include_dirs=[np.get_include()]
) 

cmd到setup.py文件夹下,然后使用命令

python setup.py build_ext  --inplace

将_multiotsu.cp35-win_amd64.pyd复制到与_multiotsu.pyx同一文件夹下,然后重命名为_multiotsu.pyd。

具体如何使用请参考:https://blog.csdn.net/u013066730/article/details/103462952

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!