2 min read

CUDA image 처리

CUDA image 처리

회사서 간단하게 발표자료를 만들면서 쿠다 프로그래밍을 해보았습니다.

근데 node회사라는게 함정입니다.

간단한 영상을 미러링 해주는 프로그램입니다.

#include <iostream>
#include <iostream>
#include <chrono>
#include <vector>
#include <thread>

#include "bitmap_image.hpp"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"


// GTX 1060 thread Count is 128
#define THREAD_SIZE_X 32
#define THREAD_SIZE_Y 4


bitmap_image gpuToBitImage(uchar4* gpuPoint, int row, int col);
uchar4* gpuLoad(bitmap_image& image) {
	std::vector<uchar4> imageBuket;
	size_t size = image.width() * image.height();
	imageBuket.reserve(size);

	for (int y = 0; y < image.height(); ++y) {
		for (int x = 0; x < image.width(); ++x) {
			rgb_t colour;
			image.get_pixel(x, y, colour);
			imageBuket.push_back({ colour.red,colour.green,colour.blue,0 });
		}
	}

	uchar4* gpuMmeory = nullptr;
	cudaMalloc((void**)&gpuMmeory, sizeof(uchar4) * image.width() * image.height());
	cudaMemcpy(gpuMmeory, &(imageBuket[0]), sizeof(uchar4) * image.width() * image.height(), cudaMemcpyHostToDevice);

	return gpuMmeory;

}

__global__
void mirror(const uchar4* org, uchar4* result, int row, int col) {

	int tCol = blockDim.x * blockIdx.x + threadIdx.x;
	int tRow = blockDim.y * blockIdx.y + threadIdx.y;


	if (tCol >= col || tRow >= row) {
		return;
	}

	int posion = tRow * col + tCol;

	int resultPosion = (tRow * col) + (col - tCol);

	result[resultPosion] = org[posion];

}

bitmap_image gpuToBitImage(uchar4* gpuPoint, int col, int row) {
	bitmap_image image(col, row);

	std::vector<uchar4> imageBuket;
	imageBuket.resize(row * col);
	cudaMemcpy(&(imageBuket[0]), gpuPoint, sizeof(uchar4) * row * col, cudaMemcpyDeviceToHost);

	for (int y = 0; y < image.height(); ++y)
	{
		for (int x = 0; x < image.width(); ++x)
		{
			uchar4 color = imageBuket[(y * col) + x];
			image.set_pixel(x, y, color.x, color.y, color.z);
		}
	}

	return image;
}
bitmap_image mirrorImple(bitmap_image& image) {

	uchar4* gpuPoint = gpuLoad(image);

	uchar4* gpuResultPoint;

	cudaMalloc((void**)&gpuResultPoint, sizeof(uchar4) * image.width() * image.height());

	dim3 thread(THREAD_SIZE_X, THREAD_SIZE_Y);
	dim3 grid(
		(image.width() / THREAD_SIZE_X) + 1,
		(image.height() / THREAD_SIZE_Y) + 1
	);

	mirror << <grid, thread >> > (gpuPoint, gpuResultPoint, image.height(), image.width());

	bitmap_image result = gpuToBitImage(gpuResultPoint, image.width(), image.height());

	cudaFree(gpuPoint);
	cudaFree(gpuResultPoint);

	return result;
}

int main()
{
	bitmap_image image("image.bmp");

	if (!image)
	{
		printf("Error - Failed to open: input.bmp\n");
		return 1;
	}


	bitmap_image result = mirrorImple(image);
	result.save_image("asdsad.bmp");

	return 0;

}

실행 결과는 아래와 같습니다.

가우시안 블루같은경우도 해당 코드를 가져가서 사용하면 쉽게(?) 사용할수 있을것입니다.

이미지 처리는 아래 bitmap이미지를 사용했습니다.

https://github.com/ArashPartow/bitmap/blob/master/bitmap_image.hpp

1060 GTX가 블록단 스레드가 128이 한계라서 스레드 사이즈를 32 * 4로 하였습니다.

Warp단위라 속도가 빠를겁니다.