前言
图像数据处理由于处理繁琐,数据量大,为了不占用cpu资源,一般由硬件模块处理,或者由GPU做处理。但是,对于一些简单的处理操作,我们还是有必要学习一下,因为有些简单场景没有必要调用硬件资源。以下操作虽然简单,但是我也调试了千万遍,才知道“纸上得来终觉浅,绝知此事要躬行”。
一、RGB的flip操作
LOCAL void _rgb_flip(uint16 *addr,int width,int height)
{
uint8 i = 0, j = 0;
uint16 tmp_data = 0;
for(i = 0;i < height;i++)
{
for(j = 0;j < width / 2;j++)
{
tmp_data = *(addr + j);
*(addr + j) = *(addr + width - j - 1);
*(addr + width - j - 1) = tmp_data;
}
addr += width;
}
}
rgb的存储格式是一个像素点对应一个数据存储,例如,RGB565的存储格式如下,所以一个像素点占俩字节,该算法也只适用565格式,不适用888格式
rgb565存储格式
二、YUV的填充操作
void _ISP_YUV420pFillBlack(ISP_ADDRESS_T *src, ISP_ADDRESS_T *dst,
uint32 src_w, uint32 src_h, uint32 dst_w, uint32 dst_h)
{
uint32 s_y = src->yaddr, s_u = src->uaddr;
uint32 d_y = dst->yaddr, d_u = dst->uaddr;
uint8 y_value = 0, u_value = 128; //black
if (dst_w > src_w && dst_h == src_h && (dst_w - src_w) % 4 == 0) {
ISPSRV_LOGI("Fill in width");
uint32 offset = (dst_w - src_w) >> 1;
uint32 offset_ = dst_w - src_w - offset;
for (int i = 0; i < dst_h; i++){
SCI_MEMSET((void *)d_y, y_value, offset);
d_y += offset;
SCI_MEMCPY((void *)d_y, s_y, src_w);
d_y += src_w, s_y += src_w;
SCI_MEMSET((void *)d_y, y_value, offset_);
d_y += offset_;
SCI_MEMSET((void *)d_u, u_value, offset >> 1);
d_u += offset >> 1;
SCI_MEMCPY((void *)d_u, s_u, src_w>>1);
d_u += src_w>>1, s_u += src_w>>1;
SCI_MEMSET((void *)d_u, u_value, offset_ >> 1);
d_u += offset_ >> 1;
}
} else if (dst_w == src_w && dst_h > src_h && (dst_h - src_h) % 4 == 0) {
ISPSRV_LOGI("Fill in height");
uint32 offset = (dst_h - src_h)>>1;
uint32 offset_ = dst_h - src_h - offset;
SCI_MEMSET((void *)d_y, y_value, offset * dst_w);
d_y += offset * dst_w;
SCI_MEMCPY((void *)d_y, s_y, src_w * src_h);
d_y += dst_w * src_h;
SCI_MEMSET((void *)d_y, y_value, offset_ * dst_w);
d_y += offset_ * dst_w;
SCI_MEMSET((void *)d_u, u_value, (offset * src_w) >>1);
d_u += (offset * src_w) >>1;
SCI_MEMCPY((void *)d_u, s_u, (src_w * src_h) >> 1);
d_u += (src_w * src_h) >> 1;
SCI_MEMSET((void *)d_u, u_value, (offset_ * src_w)>>1);
d_u += (offset_ * src_w)>>1;
} else {
ISPSRV_LOGE("Size error !!!");
}
}
该填充操作上半部分是未经过验证的,应该还存在问题,贴上去只为了凑点字数,看Fill in height即可
三、YUV的裁剪操作
void _ISP_YUV420pCutBlack(ISP_ADDRESS_T *src, ISP_ADDRESS_T *dst,
uint32 src_w, uint32 src_h, uint32 dst_w, uint32 dst_h)
{
uint32 s_y = src->yaddr, s_u = src->uaddr;
uint32 d_y = dst->yaddr, d_u = dst->uaddr;
uint8 y_value = 0,u_value = 128;
uint32 width = 0,height = 0;
ISPSRV_LOGI("cut in width");
uint32 offset = (src_w - dst_w)>>1;
uint32 offset_ = src_w - dst_w - offset;
s_y += offset;
for(height = 0;height < dst_h;height++)
{
SCI_MEMCPY(d_y,s_y,dst_w);
d_y += dst_w;
s_y += src_w;
}
s_u += offset;
for(height = 0;height < (dst_h >> 1);height++)
{
SCI_MEMCPY(d_u,s_u,dst_w);
d_u += dst_w;
s_u += src_w;
}
}
针对YUV的填充和裁剪,最重要的就是要搞清楚YUV的数据存储格式,以上算法也是针对YUV420格式的
yuv420存储格式
之前参考别人代码,纳闷为什么只对y和u地址操作,而不做v地址操作,仔细一看会发现做u地址处理时已经把v数据也处理了。
网友评论