Nvidia Video Codec SDK——AppDecImageProvider动态模糊
Cpp文件
初始化变量:
平滑函数Bgra32ToSmooth,注意f和deep都转化为指针类型,因为数据在显存读取:
Bgra32ToSmooth((uint8_t *)ppFrame_Deep[i],(uint8_t*)pTmpImage,(uint8_t*)sTmpImage, 4 * dec.GetWidth(), dec.GetWidth(), dec.GetHeight(), x_position, y_position, v, d, (float *)f, far_distance, near_distance, (int *)deep);
cu文件
void Bgra32ToSmooth(uint8_t *yuvDeep, uint8_t *dpBgra, uint8_t *smoothBgra, int nBgraPitch, int nWidth, int nHeight, int x_position, int y_position,float v,float d, float *f, int far_distance, int near_distance, int *deep) {
focalLength <<<1, 1 >>> (yuvDeep, x_position, y_position, v, f, far_distance, near_distance, deep, nWidth);
Bgra32ToSmoothKernel
<<<dim3((nWidth + 127) / 128, (nHeight + 7) / 8), dim3(128, 8)>>>
(yuvDeep, dpBgra, smoothBgra, x_position, y_position, nBgraPitch, nWidth, nHeight, f, d, far_distance, near_distance, deep);
}
核函数focalLength——获得注视点对应深度
focalLength <<<1, 1 >>> (yuvDeep, x_position, y_position, v, f, far_distance, near_distance, deep, nWidth);
__global__ static void focalLength(uint8_t *yuvDeep, int x_position, int y_position, float v, float *f, int far_distance, int near_distance, int *deep,int nWidth) {
*deep = (far_distance*near_distance) / (near_distance + (far_distance - near_distance)*yuvDeep[x_position + y_position*nWidth]/255.0f);
*f = *deep * v / (*deep + v);
}
核函数Bgra32ToSmooth
Bgra32ToSmoothKernel
<<<dim3((nWidth + 127) / 128, (nHeight + 7) / 8), dim3(128, 8)>>>
(yuvDeep, dpBgra, smoothBgra, x_position, y_position, nBgraPitch, nWidth, nHeight, f, d, far_distance, near_distance, deep);
__global__ static void Bgra32ToSmoothKernel(uint8_t *yuvDeep,uint8_t *pRgb, uint8_t *sRgb, int x_position, int y_position, int nBgraPitch, int nWidth, int nHeight, float *f, float d, int far_distance, int near_distance,int *depth) {
int x = threadIdx.x + blockIdx.x * blockDim.x;//宽方向
int y = threadIdx.y + blockIdx.y * blockDim.y;//高方向
if (x + 1 >= nWidth || y + 1 >= nHeight) {
return;
}
int Index = x * 4 + y * nBgraPitch;//当前像素点的位置
sRgb[Index] = pRgb[Index];
sRgb[Index + 1] = pRgb[Index + 1];
sRgb[Index + 2] = pRgb[Index + 1];
sRgb[Index + 3] = pRgb[Index + 3];
//缩放因子,距离时乘以缩放因子,弥散圆时除以缩放因子
float alpha = cos(asin(abs(y - nHeight / 2) / (float)(nWidth / 4)));//距离缩放因子,越靠近南北极点值越小(该距离是以二维纹理距离为基准的,基线为纹理中心水平线,因此alpha<=1)
float dist = dis(x, y, x_position, y_position, nWidth, alpha);//当前计算像素点与注视点的距离
int currentDepth = (far_distance*near_distance) / (near_distance + (far_distance - near_distance)*yuvDeep[x + y*nWidth] / 255.0);//计算当前像素点的深度值
float blurCircle = getRadius(currentDepth, depth, f, d) / (alpha < 0.1 ? 0.1 : alpha) * 300;//计算弥散圆半径,返回blurCiecle最大值在0.067左右,因此乘以一个放大因子
float radius = sqrtf(dist * dist + blurCircle * blurCircle);
unsigned int sum_r = 0, sum_g = 0, sum_b = 0, count = 0;
int rightUp = 0, leftUp = 0, rightLow = 0, leftLow = 0;
for (int m = 0; m < radius; m++) {
for (int n = 0; n < radius; n++) {
rightUp = rightUpIndex(x + m, y + n, nWidth, nHeight, nBgraPitch);
leftUp = leftUpIndex(x - m, y + n, nWidth, nHeight, nBgraPitch);
rightLow = rightLowIndex(x + m, y - n, nWidth, nHeight, nBgraPitch);
leftLow = leftLowIndex(x - m, y - n, nWidth, nHeight, nBgraPitch);
sum_r = sum_r + pRgb[rightUp] + pRgb[leftUp] + pRgb[rightLow] + pRgb[leftLow];
sum_g = sum_g + pRgb[rightUp + 1] + pRgb[leftUp + 1] + pRgb[rightLow + 1] + pRgb[leftLow + 1];
sum_b = sum_b + pRgb[rightUp + 2] + pRgb[leftUp + 2] + pRgb[rightLow + 2] + pRgb[leftLow + 2];
count += 4;
}
}
sum_r = average_color(sum_r, count);
sum_g = average_color(sum_g, count);
sum_b = average_color(sum_b, count);
if (sum_r != 0 || sum_g != 0 || sum_b != 0) { //如果sum均为0,则radius=0,保持原来的值不变
sRgb[x * 4 + y * nBgraPitch] = (uint8_t)sum_r;
sRgb[x * 4 + y * nBgraPitch + 1] = (uint8_t)sum_g;
sRgb[x * 4 + y * nBgraPitch + 2] = (uint8_t)sum_b;
}
//printf("radius = %f, ", radius);
//printf("%d, ",yuvDeep[x + y * nWidth]);
}
其中各函数如下:
计算各像素点之间的距离dis函数:
__device__ float dis(int x,int y,int x_position, int y_position, int width, float alpha){
int x_dis =alpha * (abs(x - x_position) < width/2 ? abs(x - x_position) : width - abs(x - x_position));
return sqrtf((x_dis)*(x_dis) + (y - y_position)*(y - y_position))/100;
}
计算弥散圆直径getRadius函数
__device__ inline float getRadius(int currentDepth, int *depth, float *f, float d){
return (currentDepth - *depth) > 0 ? f[0]*d*(currentDepth - *depth) / (*depth*currentDepth) : f[0]*d*(*depth - currentDepth) / (*depth*currentDepth);
}
沿各方向搜索,确定像素点跳变函数
__device__ int rightUpIndex(int x, int y, int width, int height, int nBgraPitch) {
x = (x >= width ? x - width : x);//如果x超出边界则取到的点为x-width
if (y >= height) { //如果y超出边界,不仅y值会改变,x也会改变
y = 2 * height - y - 1;
x = width - x;
}
return x * 4 + y*nBgraPitch;
}
__device__ int leftUpIndex(int x, int y, int width, int height, int nBgraPitch){
x = (x < 0 ? x + width : x);
if (y >= height) {
y = 2 * height - y - 1;
x = width - x;
}
return x * 4 + y*nBgraPitch;
}
__device__ int rightLowIndex(int x, int y, int width, int height, int nBgraPitch) {
x = (x >= width ? x - width : x);
if (y < 0) {
y = -y;
x = width - x;
}
return x * 4 + y*nBgraPitch;
}
__device__ int leftLowIndex(int x, int y, int width, int height, int nBgraPitch) {
x = (x < 0 ? x + width : x);
if (y < 0) {
y = -y;
x = width - x;
}
return x * 4 + y*nBgraPitch;
}
__device__ inline int average_color(int sum,int count){
return count == 0 ? sum : (sum / count);
}
注意在x方向存在的跳变只与x有关,当搜索x大于width或小于0时,对应的像素点变为(x+width)%width
在y方向存在的跳变不仅与y有关,还与x有关。当y大于height时,y变为2 * height - y - 1;当y小于0时,y变为-y。当y发生跳变时,x变为width-x,即x跳变后的点与跳变前的点关于x=width/2对称。
缩放因子alpha:
float alpha = cos(asin(abs(y - nHeight / 2) / (float)(nWidth / 4)));
在南北极方向,x轴存在较大畸变:
对于小凹成像特性,南北极点的畸变导致在球体上离得十分近的两点,由于畸变原因,映射回二维纹理时可能离得非常远,由于我们计算距离时是按照二维纹理上各像素点的距离计算的,因此distance要乘以alpha。
对于深度差与模糊度的关系,由于我们计算的弥散圆直径实际是计算的球体上的弥散圆直径(现实生活中观察的场景相当于观察球体上的纹理),而最终计算的时候是按照二维纹理上的弥散圆计算的,因此导致在南北极点球体上弥散圆包含了大量的点,而二维纹理上计算弥散圆时只包含了少量的点。因此弥散圆直径radius要除以alpha。