#include "device_functions.h"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "stdlib.h"
#include <string>
#include <cassert>
#include <iostream>
using namespace std;
#include <opencv2\opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
//求解公式: .299f*R+.587f*G+.114*B
cv::Mat imageRGBA;
cv::Mat imageGrey;
//返回RGBA照片的行数
size_t numRows()
{
return imageRGBA.rows;
}
//返回照片的列数
size_t numCols()
{
return imageRGBA.cols;
}
void preProcess(uchar4 **inputImage, unsigned char **greyImage, uchar4 **d_rgbaImage, unsigned char **d_greyImage, const string &filename)
{
//Mat对象
cv::Mat image;
//读取image
image = cv::imread(filename.c_str(), CV_LOAD_IMAGE_COLOR);
if (image.empty())
{
cerr << "读取照片失败:" << filename << endl;
exit(1);
}
//将BGR转换成RGB
cv::cvtColor(image, imageRGBA, CV_BGR2RGBA);
//构造一个和RGB一样大的灰度照片
imageGrey.create(image.rows, image.cols, CV_8UC1);
if (!imageRGBA.isContinuous() || !imageGrey.isContinuous())
{
cerr << "空间不连续" << endl;
exit(1);
}
//将imageRGBA的地址传出去目的是将Mat转换成数组
*inputImage = (uchar4*)imageRGBA.ptr<unsigned char>(0);
*greyImage = imageGrey.ptr<unsigned char>(0);
//记录照片的大小
const size_t numPixels = numCols()*numRows();
//在Device 上开辟内存
cudaMalloc(d_rgbaImage, sizeof(uchar4)*numPixels);
cudaMalloc(d_greyImage, sizeof(unsigned char)*numPixels);
//将d_greyImage全都初始化成0
cudaMemset(*d_greyImage, 0, numPixels * sizeof(unsigned char));
//为d_rgbaImage赋值
cudaMemcpy(*d_rgbaImage, *inputImage, sizeof(uchar4)*numPixels, cudaMemcpyHostToDevice);
}
__global__ void rgba_to_greyscale(uchar4* const rgbaImage, unsigned char *const greyImage, int numRows, int numCols)
{
//获取每个线程的ID方法一
//const int idx = blockIdx.x*blockDim.x + threadIdx.x;
//const int idy = blockIdx.y*blockDim.y + threadIdx.y;
//const int id = idx * numCols + idy;
//方法二
const int id = blockIdx.x*blockDim.x*blockDim.y + threadIdx.y*blockDim.x + threadIdx.x;
if (id < numRows*numCols)
{
const unsigned char R = rgbaImage[id].x;
const unsigned char G = rgbaImage[id].y;
const unsigned char B = rgbaImage[id].z;
greyImage[id] = .299f*R + .587f*G + .114*B;
}
}
//保存照片
void postProcess(string &outPut_file, unsigned char *greyImage)
{
//将数组转换成Mat
cv::Mat outImage(numRows(), numCols(), CV_8UC1,(void*)greyImage);
cv::imwrite(outPut_file.c_str(), outImage);
//显示处理好的照片
imshow("sucessed", outImage);
waitKey(0);
}
int main(string *input)
{
string input_file = "E:\\ZC\\procedure\\CUDA\\Images\\1.png";//这个地方写你自己照片的的路径
string output_file = "E:\\ZC\\procedure\\CUDA\\Images\\2.png";//你要保存的路径
uchar4* h_rgbaImage, *d_rgbaImage;
unsigned char *h_greyImage, *d_greyImage;
preProcess(&h_rgbaImage, &h_greyImage, &d_rgbaImage, &d_greyImage, input_file);
const int thread = 16;
const int grid = (numRows()*numCols() + thread - 1) / (thread*thread);
const dim3 blockSize(thread, thread);
const dim3 gridSize(grid);
rgba_to_greyscale << <gridSize, blockSize >> > (d_rgbaImage, d_greyImage, numRows(), numCols());
//等待线程全部结束
cudaDeviceSynchronize();
//将结果传回Host上
cudaMemcpy(h_greyImage, d_greyImage, sizeof(unsigned char)*numRows()*numCols(), cudaMemcpyDeviceToHost);
postProcess(output_file, h_greyImage);
//cleanup();
cudaFree(d_rgbaImage);
cudaFree(d_rgbaImage);
}
处理前:
处理后: