1 對 IVE_IMAGE_S 的分析
這部分內容來自海思文檔 HiIVE API 參考 ,文檔中有更多圖像類型的說明內容。
說明
定義二維廣義圖像信息。
定義
typedef struct hiIVE_IMAGE_S
{
HI_U64 au64PhyAddr[3]; /* RW;The physical address of the image */
HI_U64 au64VirAddr[3]; /* RW;The virtual address of the image */
HI_U32 au32Stride[3]; /* RW;The stride of the image */
HI_U32 u32Width; /* RW;The width of the image */
HI_U32 u32Height; /* RW;The height of the image */
IVE_IMAGE_TYPE_E enType; /* RW;The type of the image */
}IVE_IMAGE_S;
成員
成員名稱 | 描述 |
---|---|
au64PhyAddr[3] | 廣義圖像的物理地址數組 |
au64VirAddr[3] | 廣義圖像的虛擬地址數組 |
au32Stride[3] | 廣義圖像的跨度 |
u32Width | 廣義圖像的寬度 |
u32Height | 廣義圖像的高度 |
enType | 廣義圖像的圖像類型 |
二維廣義圖像類型表
類型 | 圖像描述 | 內存地址 | 跨度 |
---|---|---|---|
IVE_IMAGE_TYPE_U8C1 | 8bit 無符號單通道圖像 | 僅用到 IVE_IMAGE_S 中的 au64PhyAddr[0]、au64VirAddr[0] | 僅用到 u32Stride[0] |
圖像描述
如果圖片類型爲 IVE_IMAGE_TYPE_U8C1 時,n 取 8。
關於對 Width 和 Stride 的理解,請參考 yuv 圖像裏的stride和plane的解釋
2 代碼實現
根據上一小節的分析,我們知道 Width 是小於等於 Stride 的。當輸入的圖片格式是 U8C1 時,圖片的 Width 等於 Stride。當然下面的代碼也可以進一步簡化。
這裏的代碼是想參考 opencv 的 countNonZero 函數,返回值是灰度值不爲0的像素數。同時也打印出各個像素點的灰度值。
但是此方法耗時過長,對720x576的圖像處理一次時間爲0.28s,推薦使用3 使用海思 IVE 實現 countNonZero
代碼
/*
As we all know, au32Stride[0] greater than u32Width
*/
static HI_U32 CountNonZero(IVE_IMAGE_S *pstImg)
{
HI_U16 u16Row;
HI_U16 u16List;
HI_U8* u8copy; //read
HI_U8* u8origin; //change line
HI_U16 height;
HI_U16 width;
HI_U16 NonZeroCount = 0;
height = pstImg->u32Height;
width = pstImg->u32Width;
u8copy = (HI_U8 *)(HI_UL)pstImg->au64VirAddr[0];
u8origin = (HI_U8 *)(HI_UL)pstImg->au64VirAddr[0];
for (u16Row = 0; u16Row < height; ++u16Row)
{
for(u16List = 0; u16List < width; ++u16List)
{
printf("%d ", *u8copy);
if(*u8copy != 0)
{
NonZeroCount++;
}
u8copy += 1;
}
printf("\n");
u8origin += pstImg->au32Stride[0]; //switch to the next line
u8copy = u8origin;
}
return NonZeroCount;
}
效果
- 先使用 CV 生成一張 64x64 的圖像,其中 10~19 行是黑色部分。
#include <iostream>
#include <stdio.h>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat image(64, 64, CV_8UC1);
for (int i = 0; i < image.rows; i++)
{
uchar* p = image.ptr<uchar>(i);
for (int j = 0; j < image.cols; j++)
{
if (i < 20 && i>=10)
{
p[j] = 0;
}
else
{
p[j] = 255;
}
}
}
imwrite("demo.jpg", image);
return 0;
}
- 轉化爲 yuv 格式圖像
ffmpeg -i demo.jpg -pix_fmt gray demo.yuv
- 結果
3 使用海思 IVE 實現 countNonZero
閱讀文檔後發現,海思已經提供了類似的統計函數(我哭了)
HI_S32 HI_MPI_IVE_Hist(IVE_HANDLE *pIveHandle, IVE_SRC_IMAGE_S *pstSrc, IVE_DST_MEM_INFO_S *pstDst, HI_BOOL bInstant);
計算公式:
在使用前需要聲明和初始化數組 IVE_DST_MEM_INFO_S stCount
,使用完需要釋放
在程序中的具體位置可以參閱海思Hi3519A開發(11.海思IVE使用模板總結(FILE->IVE->FILE))
//在 hiSAMPLE_IVE_SFD_S 結構體裏裏聲明
IVE_DST_MEM_INFO_S stCount;
//在 SAMPLE_IVE_Sfd_Uninit 函數裏釋放
IVE_MMZ_FREE(pstSfd->stCount.u64PhyAddr, pstSfd->stCount.u64VirAddr);
//在 SAMPLE_IVE_Sfd_Init 函數裏初始化
HI_U32 u32Size = IVE_HIST_NUM * sizeof(HI_U32);
s32Ret = SAMPLE_COMM_IVE_CreateMemInfo(&(pstSfd->stCount), u32Size);
SAMPLE_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret, SFD_INIT_FAIL, "Error(%#x),Create Count mem info failed!\n", s32Ret);
HI_MPI_IVE_Hist 的具體使用,輸入爲統計用的數組 stCount 和待測試圖片 pstImg,返回值爲灰度值爲255的像素個數。
static HI_U32 SAMPLE_IVE_Count(IVE_DST_MEM_INFO_S stCount, IVE_SRC_IMAGE_S *pstImg)
{
HI_S32 s32Ret;
HI_U32 Num;
HI_U32* pu32Count;
IVE_HANDLE IveHandle;
HI_BOOL bBlock = HI_TRUE;
HI_BOOL bFinish = HI_FALSE;
s32Ret = HI_MPI_IVE_Hist(&IveHandle, pstImg, &stCount, HI_TRUE);
SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,"Error(%#x),HI_MPI_IVE_Hist failed!\n",s32Ret);
s32Ret = HI_MPI_IVE_Query(IveHandle, &bFinish, bBlock);
while (HI_ERR_IVE_QUERY_TIMEOUT == s32Ret)
{
s32Ret = HI_MPI_IVE_Query(IveHandle, &bFinish, bBlock);
}
SAMPLE_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,"Error(%#x),HI_MPI_IVE_Query failed!\n",s32Ret);
pu32Count = SAMPLE_COMM_IVE_CONVERT_64BIT_ADDR(HI_U32, stCount.u64VirAddr);
Num = *(pu32Count + 255);
return Num;
}
使用舉例
HI_U32 CntNonZero;
CntNonZero = SAMPLE_IVE_Count(pstSfd->stCount, &pstSfd->FgImg);