#c #image-processing #cuda #convolution
#c #обработка изображений #cuda #свертка
Вопрос:
Я пытаюсь свернуть изображение с помощью CUDA, но не могу получить результат. cuda-gdb не работает должным образом в моей системе, поэтому я не могу сказать, что происходит внутри ядра CUDA. Ядро CUDA, которое я использую, выглядит следующим образом:
__global__
void
convolve_component_EXTEND_kern(const JSAMPLE *data, // image data
ssize_t data_width, // image width
ssize_t data_height, // image height
const float *kern, // convolution kernel data
ssize_t kern_w_f, // convolution kernel has a width of 2 * kern_w_f 1
ssize_t kern_h_f, // convolution_kernel has a height of 2 * kern_h_f 1
JSAMPLE *res) // array to store the result
{
ssize_t i = ::blockIdx.x * ::blockDim.x ::threadIdx.x;
ssize_t j = ::blockIdx.y * ::blockDim.y ::threadIdx.y;
float value = 0;
for (ssize_t m = 0; m < 2 * kern_w_f 1; m ) {
for (ssize_t n = 0; n < 2 * kern_h_f 1; n ) {
ssize_t x = i m - kern_w_f; // column index for this contribution to convolution sum for (i, j)
ssize_t y = j n - kern_h_f; // row index for ...
x = x < 0 ? 0 : (x >= data_width ? data_width - 1 : x);
y = y < 0 ? 0 : (y >= data_height ? data_height - 1 : y);
value = ((float) data[data_width * y x]) * kern[(2 * kern_w_f 1) * n m];
}
}
res[data_width * j i] = (JSAMPLE) value;
}
и я вызываю его в этой функции
void
convolve_component_EXTEND_cuda(const JSAMPLE *data,
ssize_t data_width,
ssize_t data_height,
const float *kern,
ssize_t kern_w_f,
ssize_t kern_h_f,
JSAMPLE *res)
{
JSAMPLE *d_data;
cudaMallocManaged(amp;d_data,
data_width * data_height * sizeof(JSAMPLE));
cudaMemcpy(d_data,
data,
data_width * data_height * sizeof(JSAMPLE),
cudaMemcpyHostToDevice);
float *d_kern;
cudaMallocManaged(amp;d_kern,
(2 * kern_w_f 1) * (2 * kern_h_f 1) * sizeof(float));
cudaMemcpy(d_kern,
kern,
(2 * kern_w_f 1) * (2 * kern_h_f 1) * sizeof(float),
cudaMemcpyHostToDevice);
JSAMPLE *d_res;
cudaMallocManaged(amp;d_res,
data_width * data_height * sizeof(JSAMPLE));
dim3 threadsPerBlock(16, 16); // can be adjusted to 32, 32 (1024 threads per block is the maximum)
dim3 numBlocks(data_width / threadsPerBlock.x,
data_height / threadsPerBlock.y);
convolve_component_EXTEND_kern<<<numBlocks, threadsPerBlock>>>(d_data,
data_width,
data_height,
d_kern,
kern_w_f,
kern_h_f,
d_res);
cudaDeviceSynchronize();
cudaMemcpy(d_res,
res,
data_width * data_height * sizeof(JSAMPLE),
cudaMemcpyDeviceToHost);
cudaFree(d_data);
cudaFree(d_kern);
cudaFree(d_res);
}
В этом контексте данные изображения содержатся в массиве, называемом data, таким образом, что доступ к пикселю в (i, j) осуществляется путем индексации в массив по адресу data_width * j i. данные ядра находятся в массиве с именем kern, и его ширина равна 2 * kern_w_f 1 и высота 2 * kern_h_f 1. Доступ к элементу в (i, j) осуществляется путем индексации в массив kern по адресу (2 * w_f 1) * j i, точно так же, как и к массиву данных. Массив res используется для хранения результата свертки и выделяется с помощью calloc() перед передачей функции.
Когда я вызываю вторую функцию для данных изображения, все пиксели изображения преобразуются в 0 вместо применения свертки. Кто-нибудь может указать на проблему?
Комментарии:
1. вы уверены, что CUDA действительно работает в вашей системе? Какую версию CUDA и какой графический процессор вы используете? Почему вы используете cudaMallocManaged() с cudamempy()?
2. Я использую Cuda версии 10.1.243. Графический процессор представляет собой мобильную версию GTX1060. Что касается того, действительно ли CUDA работает, я не уверен. Когда я запускаю его, это никоим образом не указывает мне, что что-то пошло не так. Может ли CUDA автоматически завершиться сбоем?
3. Если ваша версия cuda и драйвер не работают вместе должным образом, вполне возможно, что вы не получите предупреждение о том, что не найдено CUDA-устройство (поскольку вы не проверяете наличие ошибок cuda), и тогда ядро ничего не сделает. Итак, это больше о том, можете ли вы, например, запускать образцы cuda и получать там результаты.
4. еще одно наблюдение … после обработки данных с помощью графического процессора вы вызываете cudaMemcpy(d_res,res, ..), это должно быть cudaMemcpy(res, d_res, ..), Так как вам нужно перевернуть dest и src.
Ответ №1:
Сразу после вызова ядра и выполнения свертки вы пытаетесь скопировать свои данные обратно в массив res.
cudaDeviceSynchronize();
cudaMemcpy(d_res,
res,
data_width * data_height * sizeof(JSAMPLE),
cudaMemcpyDeviceToHost);
это должно быть
cudaDeviceSynchronize();
cudaMemcpy(res,
d_res,
data_width * data_height * sizeof(JSAMPLE),
cudaMemcpyDeviceToHost);
в качестве первого аргумента cudaMemcpy используется указатель назначения.
cudaError_t cudaMemcpy ( void *dst, const void *src, size_t count, enum cudaMemcpyKind kind)
Комментарии:
1. Да, вы правы. Спасибо за замечание.