一,软件开发中,某些场景需要旋转图像,本文注意处理的是旋转图像90°,180°,270°。任意角度的旋转不涉及。注意选择观看。
图像的旋转可以利用opencv实现cpu完成,也可以通过cuda中的npp工具实现gpu完成,gpu的效率要比cpu搞很多。具体代码片段如下:
二,opencv代码实现:
1,实现如下:
void rotateImage(int degree) {
cv::Mat srcCopy;
cv::Mat src_img = imread("./bird.jpg", IMREAD_UNCHANGED);
if (degree == 90) {
cv::Mat srcCopy = cv::Mat(src_img.rows, src_img.cols, src_img.depth());
cv::transpose(src_img, srcCopy);
cv::flip(srcCopy, srcCopy, 1);
}else if (degree == 180) {
cv::Mat srcCopy = cv::Mat(src_img.rows, src_img.cols, src_img.depth());
cv::flip(src_img, srcCopy, -1);
}else if (degree == 270) {
cv::Mat srcCopy = cv::Mat(src_img.rows, src_img.cols, src_img.depth());
cv::transpose(src_img, srcCopy);
cv::flip(srcCopy, srcCopy, 0);
}
imwrite("./retOpenCV.bmp", srcCopy);
}
有的时候,是yuv数据,需要用yuv来构造Mat对象,代码如下:
Mat YuvToMat (unsigned char * pYuvData, int & width, int & height)
{
cv::Mat yuvImg;
yuvImg.create(height*3/2, width, CV_8UC1);
memcpy(yuvImg.data, pYuvData, framesize*sizeof(unsigned char));
cv::Mat rgbImg;
cv::cvtColor(yuvImg, rgbImg, CV_YUV2BGR_I420);
}
二,利用cuda的npp库实现,代码如下:
1, cuda samples里给的例子,需要用到的是freeImge第三方库:
FIBITMAP* LoadImg(const char* szFile)
{
FREE_IMAGE_FORMAT nFif;
if (szFile == NULL || *szFile == 0)
{
return NULL;
}
if ((nFif = FreeImage_GetFileType(szFile, 0)) == FIF_UNKNOWN)
{
if ((nFif = FreeImage_GetFIFFromFilename(szFile)) == FIF_UNKNOWN)
{
return NULL;
}
}
if (!FreeImage_FIFSupportsReading(nFif))
{
return NULL;
}
return FreeImage_Load(nFif, szFile);
}
void NppbyFreeImage() {
cudaError_t cuRet;
NppStatus nppRet;
BOOL fiRet = false;
FIBITMAP* pSrcBmp = NULL;
FIBITMAP* pDstBmp = NULL;
unsigned char* pSrcData = NULL;
unsigned char* pDstData = NULL;
Npp8u* pSrcDataCUDA = NULL;
Npp8u* pDstDataCUDA = NULL;
NppiSize oSrcSize = { 0 };
NppiSize oDstSize = { 0 };
NppiRect oSrcROI = { 0 };
NppiRect oDstROI = { 0 };
int nImgBpp = 0;
int nSrcPitch = 0;
int nDstPitch = 0;
int nSrcPitchCUDA = 0;
int nDstPitchCUDA = 0;
double aBoundingBox[2][2] = { 0 };
double nAngle = 0;
FreeImage_Initialise(0);
/* 载入文件 */
pSrcBmp = LoadImg("./bird.jpg");
assert(pSrcBmp != NULL);
//获取图像深度
nImgBpp = (FreeImage_GetBPP(pSrcBmp) >> 3);
cout << "freeImg nImgBpp :" << nImgBpp << endl;
//获取数据
pSrcData = FreeImage_GetBits(pSrcBmp);
oSrcSize.width = (int)FreeImage_GetWidth(pSrcBmp);
cout << "freeImg oSrcSize.width :" << oSrcSize.width << endl;
oSrcSize.height = (int)FreeImage_GetHeight(pSrcBmp);
cout << "freeImg oSrcSize.height :" << oSrcSize.height << endl;
nSrcPitch = (int)FreeImage_GetPitch(pSrcBmp);
cout << "freeImg nSrcPitch :" << nSrcPitch << endl;
oSrcROI.x = oSrcROI.y = 0;
oSrcROI.width = oSrcSize.width;
oSrcROI.height = oSrcSize.height;
nAngle = atof("90");
/* 设置显卡,构建上下文 */
cuRet = cudaSetDevice(0);
assert(cuRet == cudaSuccess);
/* 分配显存 */
int type = 0;
switch (nImgBpp)
{
case 1:
pSrcDataCUDA = nppiMalloc_8u_C1(oSrcSize.width, oSrcSize.height, &nSrcPitchCUDA);
break;
case 3:
pSrcDataCUDA = nppiMalloc_8u_C3(oSrcSize.width, oSrcSize.height, &nSrcPitchCUDA);
break;
case 4:
pSrcDataCUDA = nppiMalloc_8u_C4(oSrcSize.width, oSrcSize.height, &nSrcPitchCUDA);
break;
default:
assert(0);
break;
}
assert(pSrcDataCUDA != NULL);
/* 将原图传入显存 */
cudaMemcpy2D(pSrcDataCUDA, nSrcPitchCUDA, pSrcData, nSrcPitch, oSrcSize.width * nImgBpp, oSrcSize.height, cudaMemcpyHostToDevice);
/* 计算旋转后长宽 */
nppiGetRotateBound(oSrcROI, aBoundingBox, nAngle, 0, 0);
oDstSize.width = (int)ceil(fabs(aBoundingBox[1][0] - aBoundingBox[0][0]));
oDstSize.height = (int)ceil(fabs(aBoundingBox[1][1] - aBoundingBox[0][1]));
/* 建目标图 */
pDstBmp = FreeImage_Allocate(oDstSize.width, oDstSize.height, nImgBpp << 3);
assert(pDstBmp != NULL);
pDstData = FreeImage_GetBits(pDstBmp);
nDstPitch = (int)FreeImage_GetPitch(pDstBmp);
cout << "freeImg nDstPitch :" << nDstPitch << endl;
oDstROI.x = oDstROI.y = 0;
oDstROI.width = oDstSize.width;
cout << "freeImg oDstSize.width :" << oDstSize.width << endl;
oDstROI.height = oDstSize.height;
cout << "freeImg oDstSize.height :" << oDstSize.height << endl;
/* 分配显存 */
switch (nImgBpp)
{
case 1:
pDstDataCUDA = nppiMalloc_8u_C1(oDstSize.width, oDstSize.height, &nDstPitchCUDA);
break;
case 3:
pDstDataCUDA = nppiMalloc_8u_C3(oDstSize.width, oDstSize.height, &nDstPitchCUDA);
break;
case 4:
pDstDataCUDA = nppiMalloc_8u_C4(oDstSize.width, oDstSize.height, &nDstPitchCUDA);
break;
}
assert(pDstDataCUDA != NULL);
cudaMemset2D(pDstDataCUDA, nDstPitchCUDA, 0, oDstSize.width * nImgBpp, oDstSize.height);
/* 处理 */
switch (nImgBpp)
{
case 1:
nppRet = nppiRotate_8u_C1R(pSrcDataCUDA, oSrcSize, nSrcPitchCUDA, oSrcROI,
pDstDataCUDA, nDstPitchCUDA, oDstROI,
nAngle, -aBoundingBox[0][0], -aBoundingBox[0][1], NPPI_INTER_CUBIC);
break;
case 3:
nppRet = nppiRotate_8u_C3R(pSrcDataCUDA, oSrcSize, nSrcPitchCUDA, oSrcROI,
pDstDataCUDA, nDstPitchCUDA, oDstROI,
nAngle, -aBoundingBox[0][0], -aBoundingBox[0][1], NPPI_INTER_CUBIC);
break;
case 4:
nppRet = nppiRotate_8u_C4R(pSrcDataCUDA, oSrcSize, nSrcPitchCUDA, oSrcROI,
pDstDataCUDA, nDstPitchCUDA, oDstROI,
nAngle, -aBoundingBox[0][0], -aBoundingBox[0][1], NPPI_INTER_CUBIC);
break;
}
assert(nppRet == NPP_NO_ERROR);
cudaMemcpy2D(pDstData, nDstPitch, pDstDataCUDA, nDstPitchCUDA, oDstSize.width * nImgBpp, oDstSize.height, cudaMemcpyDeviceToHost);
fiRet = FreeImage_Save(FIF_BMP, pDstBmp, "./retFreeImage.bmp");
assert(fiRet);
nppiFree(pSrcDataCUDA);
nppiFree(pDstDataCUDA);
cudaDeviceReset();
FreeImage_Unload(pSrcBmp);
FreeImage_Unload(pDstBmp);
}
2,opencv + cuda npp,代码如下:
void NppbyOpenCV2() {
cudaError_t cuRet;
NppStatus nppRet;
BOOL fiRet = false;
unsigned char* pSrcData = NULL;
unsigned char* pDstData = NULL;
Npp8u* pSrcDataCUDA = NULL;
Npp8u* pDstDataCUDA = NULL;
NppiSize oSrcSize = { 0 };
NppiSize oDstSize = { 0 };
NppiRect oSrcROI = { 0 };
NppiRect oDstROI = { 0 };
int nImgBpp = 0;
int nSrcPitch = 0;
int nDstPitch = 0;
int nSrcPitchCUDA = 0;
int nDstPitchCUDA = 0;
double aBoundingBox[2][2] = { 0 };
double nAngle = 0;
FreeImage_Initialise(0);
/* 载入文件 */
Mat pSrcMat = imread("./bird.jpg", IMREAD_UNCHANGED);
//获取图像深度
nImgBpp = pSrcMat.channels();
cout << "freeImg nImgBpp :" << nImgBpp << endl;
//获取数据
pSrcData = pSrcMat.data;
oSrcSize.width = pSrcMat.cols;
oSrcSize.height = pSrcMat.rows;
nSrcPitch = pSrcMat.step;
oSrcROI.x = oSrcROI.y = 0;
oSrcROI.width = oSrcSize.width;
oSrcROI.height = oSrcSize.height;
nAngle = atof("90");
/* 设置显卡,构建上下文 */
cuRet = cudaSetDevice(0);
assert(cuRet == cudaSuccess);
/* 分配显存 */
int type = 0;
switch (nImgBpp)
{
case 1:
pSrcDataCUDA = nppiMalloc_8u_C1(oSrcSize.width*nImgBpp, oSrcSize.height, &nSrcPitchCUDA);
break;
case 3:
pSrcDataCUDA = nppiMalloc_8u_C3(oSrcSize.width*nImgBpp, oSrcSize.height, &nSrcPitchCUDA);
break;
case 4:
pSrcDataCUDA = nppiMalloc_8u_C4(oSrcSize.width*nImgBpp, oSrcSize.height, &nSrcPitchCUDA);
break;
default:
assert(0);
break;
}
assert(pSrcDataCUDA != NULL);
/* 将原图传入显存 */
cudaMemcpy2D(pSrcDataCUDA, nSrcPitchCUDA, pSrcData, nSrcPitch, oSrcSize.width*nImgBpp, oSrcSize.height, cudaMemcpyHostToDevice);
/* 计算旋转后长宽 */
nppiGetRotateBound(oSrcROI, aBoundingBox, nAngle, 0, 0);
oDstSize.width = (int)ceil(fabs(aBoundingBox[1][0] - aBoundingBox[0][0]));
oDstSize.height = (int)ceil(fabs(aBoundingBox[1][1] - aBoundingBox[0][1]));
/* 建目标图 */
Mat pDstMat(oDstSize.height, oDstSize.width, pSrcMat.type());
pDstData = pDstMat.data;
nDstPitch = pDstMat.step;
oDstROI.x = oDstROI.y = 0;
oDstROI.width = oDstSize.width;
oDstROI.height = oDstSize.height;
/* 分配显存 */
switch (nImgBpp)
{
case 1:
pDstDataCUDA = nppiMalloc_8u_C1(oDstSize.width, oDstSize.height, &nDstPitchCUDA);
break;
case 3:
pDstDataCUDA = nppiMalloc_8u_C3(oDstSize.width, oDstSize.height, &nDstPitchCUDA);
break;
case 4:
pDstDataCUDA = nppiMalloc_8u_C4(oDstSize.width, oDstSize.height, &nDstPitchCUDA);
break;
}
assert(pDstDataCUDA != NULL);
cudaMemset2D(pDstDataCUDA, nDstPitchCUDA, 0, oDstSize.width * nDstPitch, oDstSize.height);
/* 处理 */
switch (nImgBpp)
{
case 1:
nppRet = nppiRotate_8u_C1R(pSrcDataCUDA, oSrcSize, nSrcPitchCUDA, oSrcROI,
pDstDataCUDA, nDstPitchCUDA, oDstROI,
nAngle, -aBoundingBox[0][0], -aBoundingBox[0][1], NPPI_INTER_CUBIC);
break;
case 3:
nppRet = nppiRotate_8u_C3R(pSrcDataCUDA, oSrcSize, nSrcPitchCUDA, oSrcROI,
pDstDataCUDA, nDstPitchCUDA, oDstROI,
nAngle, -aBoundingBox[0][0], -aBoundingBox[0][1], NPPI_INTER_CUBIC);
break;
case 4:
nppRet = nppiRotate_8u_C4R(pSrcDataCUDA, oSrcSize, nSrcPitchCUDA, oSrcROI,
pDstDataCUDA, nDstPitchCUDA, oDstROI,
nAngle, -aBoundingBox[0][0], -aBoundingBox[0][1], NPPI_INTER_CUBIC);
break;
}
assert(nppRet == NPP_NO_ERROR);
cudaMemcpy2D(pDstData, nDstPitch, pDstDataCUDA, nDstPitchCUDA, oDstSize.width*nImgBpp, oDstSize.height, cudaMemcpyDeviceToHost);
imwrite("./retOpenCV2_90.bmp", pDstMat);
assert(fiRet);
nppiFree(pSrcDataCUDA);
nppiFree(pDstDataCUDA);
cudaDeviceReset();
}