图像处理之水彩画特效生成算法
生活随笔
收集整理的這篇文章主要介紹了
图像处理之水彩画特效生成算法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ?在研究非真實感繪制相關算法時,水彩畫算法是第一個開始看的,不過卻拖到最后總結。水彩畫還是挺不好模擬的,里面涉及的算法比較多,本文實現的水彩畫算法主要參考下面兩篇文章,《Interactive watercolor rendering?with temporal coherence and abstraction》 、《Towards Photo Watercolorization?with Artistic Verisimilitude》 ,第一篇文章比較早,第二篇文章比較新,通過這兩篇文章,可以對水彩畫的模擬過程有一個大概了解。不過由于涉及的環節比較多,在實現過程中,有些地方做了簡化,又新增了一些計算環節,總體上得到效果和文章比,并不是嚴格一致,不過本文實現的水彩畫算法運行較慢,還是比較耗時的。
? ? ? ?水彩畫算法主要涉及的計算環節有:(1)簡化細節;(2)邊緣抖動;(3)邊緣加深;(4)顏料分散;(5)紊流效果;(6)疊加紙張紋理等。上述環節中,簡化細節是非常耗時的,主要是采用了meanshift及各向異性的Kuwahara濾波原因,或許有更好的替代方法,有待優化。本文很多地方使用了噪聲,主要用到了高斯噪聲及柏林噪聲,主要用于模擬邊緣抖動、顏料分散及紊流效果。邊緣抖動有點類似前文水面倒影算法中的置換濾鏡,主要模擬顏料的流動效果。邊緣加深主要模擬顏料停止流動后,在邊緣處的沉淀痕跡。顏料分散及紊流效果,主要是模擬水彩顏料滲透效果。不過本文實現的算法,顏料分散做的不是很滿意,離真實水彩畫那種顏料擴散及滲透效果還有很大差距。
? ? ? ?下面是部分示例代碼:
void* WaterColorThread(void *arg)
{WaterColorInfo *watercolor_info = (WaterColorInfo *)arg;BMPINFO *pSrcBitmap = watercolor_info->pSrcBitmap;BMPINFO *pPaperBitmap = watercolor_info->pPaperBitmap;float *noise_perlin = watercolor_info->noise_perlin;float *mean = watercolor_info->mean;float *stdev = watercolor_info->stdev;int color_index = watercolor_info->color_index;int thread_id = watercolor_info->thread_id;int block_count = watercolor_info->block_count;// 數據轉換int width = pSrcBitmap->lWidth;int height= pSrcBitmap->lHeight;int size = width*height;float *rdata = (float *)malloc(size * sizeof(float));float *gdata = (float *)malloc(size * sizeof(float));float *bdata = (float *)malloc(size * sizeof(float));ConvertToFloat(pSrcBitmap, rdata, gdata, bdata);// 簡化細節Abstraction(rdata, gdata, bdata, mean, stdev, width, height, color_index, thread_id);// 邊緣抖動EdgeWobbling(rdata, gdata, bdata, noise_perlin, width, height, block_count);// 邊緣加深EdgeDarkening(rdata, gdata, bdata, 1.5f, width, height);// 顏料分散PigmentDispersion(rdata, gdata, bdata, 0.5f, width, height);// 紊流效果TurbulenceFlow(rdata, gdata, bdata, noise_perlin, 2.0f, width, height);// 紙張紋理PaperTexture(rdata, gdata, bdata, pPaperBitmap, 0.225f, width, height);// 數據轉換ConvertToUchar(rdata, gdata, bdata, pSrcBitmap);// 效果微調ImageAdjust(pSrcBitmap);free(rdata);free(gdata);free(bdata);rdata = NULL;gdata = NULL;bdata = NULL;return NULL;
}? ? ? ?邊緣抖動示例代碼:
void EdgeWobbling(float *rdata, float *gdata, float *bdata, float *noise_perlin, int width, int height, int block_count)
{int size = width*height;float strengthx = width / 3.5f;float strengthy = height*block_count / 3.5f;float strength = MAX(strengthx, strengthy);float *rcopy = (float *)malloc(size * sizeof(float));float *gcopy = (float *)malloc(size * sizeof(float));float *bcopy = (float *)malloc(size * sizeof(float));memcpy(rcopy, rdata, size * sizeof(float));memcpy(gcopy, gdata, size * sizeof(float));memcpy(bcopy, bdata, size * sizeof(float));int index = 0, new_index = 0;int p_offsetx = 0, p_offsety = 0, border_w = width - 1, border_h = height - 1;float *pNoiseData = noise_perlin;for (int i = 0; i < height - 1; i++){for (int j = 0; j < width - 1; j++){index = i*width + j;pNoiseData = noise_perlin + index;float new_posx = CLAMP0255_XY(j + (*(pNoiseData + 1) - *pNoiseData) * strength, border_w);float new_posy = CLAMP0255_XY(i + (*(pNoiseData + width) - *pNoiseData) * strength, border_h);int n_posx = (int)new_posx;int n_posy = (int)new_posy;float dx = new_posx - n_posx;float dy = new_posy - n_posy;p_offsetx = (n_posx != border_w);p_offsety = (n_posy != border_h);float r0 = 0.0f, g0 = 0.0f, b0 = 0.0f, r1 = 0.0f, g1 = 0.0f, b1 = 0.0f;new_index = n_posy*width + n_posx;r0 = *(rcopy + new_index);g0 = *(gcopy + new_index);b0 = *(bcopy + new_index);r1 = *(rcopy + new_index + p_offsetx);g1 = *(gcopy + new_index + p_offsetx);b1 = *(bcopy + new_index + p_offsetx);float r2 = 0.0f, g2 = 0.0f, b2 = 0.0f, r3 = 0.0f, g3 = 0.0f, b3 = 0.0f;new_index = (n_posy + p_offsety)*width + n_posx;r2 = *(rcopy + new_index);g2 = *(gcopy + new_index);b2 = *(bcopy + new_index);r3 = *(rcopy + new_index + p_offsetx);g3 = *(gcopy + new_index + p_offsetx);b3 = *(bcopy + new_index + p_offsetx);float r_val = 0.0f, g_val = 0.0f, b_val = 0.0f, fx1 = 0.0f, fx2 = 0.0f;fx1 = r0 + (r1 - r0) * dx;fx2 = r2 + (r3 - r2) * dx;r_val = fx1 + (fx2 - fx1) * dy;fx1 = g0 + (g1 - g0) * dx;fx2 = g2 + (g3 - g2) * dx;g_val = fx1 + (fx2 - fx1) * dy;fx1 = b0 + (b1 - b0) * dx;fx2 = b2 + (b3 - b2) * dx;b_val = fx1 + (fx2 - fx1) * dy;*(rdata + index) = *(rcopy + index)*0.4f + r_val*0.6f;*(gdata + index) = *(gcopy + index)*0.4f + g_val*0.6f;*(bdata + index) = *(bcopy + index)*0.4f + b_val*0.6f;}}free(rcopy);rcopy = NULL;free(gcopy);gcopy = NULL;free(bcopy);bcopy = NULL;
}? ? ? ?邊緣加深示例代碼:
void EdgeDarkening(float *rdata, float *gdata, float *bdata, float strength, int width, int height)
{int step = width;int size = width*height;float *rcopy = (float *)malloc(size * sizeof(float));float *gcopy = (float *)malloc(size * sizeof(float));float *bcopy = (float *)malloc(size * sizeof(float));memcpy(rcopy, rdata, size * sizeof(float));memcpy(gcopy, gdata, size * sizeof(float));memcpy(bcopy, bdata, size * sizeof(float));int index = 0;float *pSrcRData = NULL, *pSrcGData = NULL, *pSrcBData = NULL;float *pNewRData = NULL, *pNewGData = NULL, *pNewBData = NULL;float *pLeftData = NULL, *pRightData = NULL, *pUpData = NULL, *pDownData = NULL;for (int i = 1; i < height - 1; i++){for (int j = 1; j < width - 1; j++){index = i*width + j;// redpNewRData = rcopy + index;pLeftData = pNewRData - 1;pRightData = pNewRData + 1;pUpData = pNewRData - step;pDownData = pNewRData + step;float gradient_r = fabs(*pRightData - *pLeftData) + fabs(*pDownData - *pUpData);// greenpNewGData = gcopy + index;pLeftData = pNewGData - 1;pRightData = pNewGData + 1;pUpData = pNewGData - step;pDownData = pNewGData + step;float gradient_g = fabs(*pRightData - *pLeftData) + fabs(*pDownData - *pUpData);// bluepNewBData = bcopy + index;pLeftData = pNewBData - 1;pRightData = pNewBData + 1;pUpData = pNewBData - step;pDownData = pNewBData + step;float gradient_b = fabs(*pRightData - *pLeftData) + fabs(*pDownData - *pUpData);// resultfloat gradient = (gradient_r + gradient_g + gradient_b)/* / 1.0f*/;pSrcRData = rdata + index;pSrcGData = gdata + index;pSrcBData = bdata + index;*pSrcRData = (float)CLAMP0255_XY(BousseauColorModel(*pSrcRData, gradient, strength), 1.0f);*pSrcGData = (float)CLAMP0255_XY(BousseauColorModel(*pSrcGData, gradient, strength), 1.0f);*pSrcBData = (float)CLAMP0255_XY(BousseauColorModel(*pSrcBData, gradient, strength), 1.0f);}}free(rcopy);rcopy = NULL;free(gcopy);gcopy = NULL;free(bcopy);bcopy = NULL;
}? ? ? ?顏料分散示例代碼:
void PigmentDispersion(float *rdata, float *gdata, float *bdata, float strength, int width, int height)
{int size = width*height;float *noise_gaussian = (float *)malloc(size * sizeof(float));GaussianNoise(noise_gaussian, width, height);float *pSrcRData = rdata, *pSrcGData = gdata, *pSrcBData = bdata;for (int i = 0; i < size; i++, pSrcRData++, pSrcGData++, pSrcBData++){*pSrcRData = (float)CLAMP0255_XY(BousseauColorModel(*pSrcRData, noise_gaussian[i], strength), 1.0f);*pSrcGData = (float)CLAMP0255_XY(BousseauColorModel(*pSrcGData, noise_gaussian[i], strength), 1.0f);*pSrcBData = (float)CLAMP0255_XY(BousseauColorModel(*pSrcBData, noise_gaussian[i], strength), 1.0f);}free(noise_gaussian);noise_gaussian = NULL;
}? ? ? ?如果顏料分散模擬的好,感覺還是有水彩畫那么點意思的,不過現在也懶得優化了,下面是一些效果圖:
? ? ? ? ?
? ? ?
? ? ?
? ? ?
? ? ?
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ?
? ??
? ??
? ? ? ?也歡迎下載示例demo:http://download.csdn.net/detail/u013085897/9747177
? ? ? ? ?
? ? ?
? ? ?
? ? ?
? ? ?
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ?
? ??
? ??
? ? ? ?也歡迎下載示例demo:http://download.csdn.net/detail/u013085897/9747177
總結
以上是生活随笔為你收集整理的图像处理之水彩画特效生成算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据分析1_猫眼TOP100
- 下一篇: dnSpy反编译EXE或DLL