Код Cython, возвращающий неверный тип данных результата после выполнения - PullRequest
0 голосов
/ 04 ноября 2019

Я пытаюсь реализовать некоторый код, который я нашел в StackOverflow (кредит Самый эффективный способ вычисления радиального профиля ), и я нахожу несколько проблем, связанных с возвращаемой переменной. Ключевым типом данных, с которым вы работаете, является 16-разрядное целое число без знака;однако, глядя на результаты, они кажутся намного выше, чем хотелось бы. Вот мой установочный код, и я компилирую его с помощью инструментов сборки Visual Studio - лучше ли будет использовать GCC, и если да, может кто-нибудь подсказать мне советы по смене компиляторов?

Код setup.py:

from distutils.core import setup
from Cython.Build import cythonize
import numpy

ext_options = {"compiler_directives": {"profile": True}, "annotate": True}
setup(
    ext_modules = cythonize("radialAvgCython.pyx", **ext_options),
    include_dirs=[numpy.get_include()]
)

Спасибо за ваше время!

РЕДАКТИРОВАТЬ 3: Я думаю, что я, возможно, нашел проблему, которая находится в одной из функций в коде Cythonic, показанном ниже:

cdef void cython_radial_profile(DTYPE_IMG_t [:, :] img_view, DTYPE_t [:] r_profile_view, int xs, int ys, int x0, int y0) nogil:

        cdef int x, y, r, tmp

        for x in prange(xs):
            for y in range(ys):
                r =<int>(sqrt((x - x0)**2 + (y - y0)**2))
                tmp = img_view[x, y]

                r_profile_view[r] +=  tmp 

Я считаю, что для каждого радиуса r значение добавляется к предыдущему значению и усреднение не происходит;Вот почему результаты, как правило, намного больше, чем ожидалось. Я попытаюсь найти способ усреднения каждого r, но я думаю, что это может быть основной проблемой, поскольку результаты существенно больше, чем другие простые азимутальные / радиальные средние коды.

РЕДАКТИРОВАТЬ 2: Воткод, используемый в radialAvgCython.pyx, насколько я могу судить, код хорошо написан, но результаты между этим и стандартным радиальным средним значением сильно различаются:

import numpy as np
cimport numpy as np
cimport cython
from cython.parallel import prange
from libc.math cimport sqrt, ceil


DTYPE_IMG = np.uint16
ctypedef np.uint16_t DTYPE_IMG_t
DTYPE = np.int
ctypedef np.int_t DTYPE_t


@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cdef void cython_radial_profile(DTYPE_IMG_t [:, :] img_view, DTYPE_t [:] r_profile_view, int xs, int ys, int x0, int y0) nogil:

    cdef int x, y, r, tmp

    for x in prange(xs):
        for y in range(ys):
            r =<int>(sqrt((x - x0)**2 + (y - y0)**2))
            tmp = img_view[x, y]

            r_profile_view[r] +=  tmp



@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def radial_profile(np.ndarray img, int centerX, int centerY):

    # Find and define image dimensions.
    cdef int xs, ys, r_max
    xs, ys = img.shape[0], img.shape[1]

    # Find maximum radius based on defined center and image size.
    cdef int topLeft, topRight, botLeft, botRight

    topLeft = <int> ceil(sqrt(centerX**2 + centerY**2))
    topRight = <int> ceil(sqrt((xs - centerX)**2 + (centerY)**2))
    botLeft = <int> ceil(sqrt(centerX**2 + (ys-centerY)**2))
    botRight = <int> ceil(sqrt((xs-centerX)**2 + (ys-centerY)**2))

    r_max = max(topLeft, topRight, botLeft, botRight)

    # Create relevant variables and feed in, solve.
    cdef np.ndarray[DTYPE_t, ndim=1] r_profile = np.zeros([r_max], dtype=DTYPE)
    cdef DTYPE_t [:] r_profile_view = r_profile
    print(r_profile)
    cdef DTYPE_IMG_t [:, :] img_view = img

    with nogil:
        cython_radial_profile(img_view, r_profile_view, xs, ys, centerX, centerY)

    # Return radial profile.
    print(r_profile)
    return r_profile

РЕДАКТИРОВАТЬ: я должен упомянуть, чтоЯ использую PyCharm в качестве своей IDE.

...