Watercolor Filter The watercolor filter algorithm is as follows: 1. Assume that the original image is F (x, y) and G (x, y) is obtained in grayscale ); 2. Construct a Radius square template M with a side length of 2 * Radius + 1; 3. Traverse each pixel of M on F sequentially. For the current pixel P (x, y ): Set the number of paint buckets to N. Since the gray scale value of the image ranges from 0 to 255, the number of paint buckets to N must be less than 255. This paint bucket is used to hold pixels of different categories. 3.1 first, the range of 0-is divided into N paint buckets according to the number of paint buckets N. For the corresponding pixels in the template, we put them in the corresponding paint buckets according to their gray values; 3.2 count the number of pixels in N paint buckets, and calculate the Mean of pixels in the paint bucket with the largest number of workers. The Mean RGB is the value of P (x, y) in the template center pixel. As follows: Fig.1 oil painting filter (N = 8) Note: The number of paint bins N can adjust the image smoothness. the Radius of the template is used to adjust the degree of watercolor painting. The preceding algorithm improves the efficiency by using the fast mean Filtering Algorithm for template traversal. The Code is as follows: Private Bitmap OilpaintFilterProcess (Bitmap srcBitmap, int radius, int smooth) { If (radius = 0) Return srcBitmap; Smooth = smooth <1? 1: smooth; Smooth = Math. Max (1, smooth ); Bitmap a = new Bitmap (srcBitmap ); Int w = srcBitmap. Width; Int h = srcBitmap. Height; If (radius> Math. Min (w, h)/2) Radius = (int) (Math. Min (w, h)/2-0.5 ); System. drawing. imaging. bitmapData srcData =. lockBits (new Rectangle (0, 0, w, h), System. drawing. imaging. imageLockMode. readWrite, System. drawing. imaging. pixelFormat. format32bppArgb ); IntPtr = srcData. Scan0; Int bytes = h * srcData. Stride; Byte [] srcValues = new byte [bytes]; System. Runtime. InteropServices. Marshal. Copy (ptr, srcValues, 0, bytes ); Byte [] tempValues = (byte []) srcValues. Clone (); Int stride = srcData. Stride; Int I, j, k; Int unit = 4; Int [] gray_bt = new int [smooth]; Int [] r_bt = new int [smooth]; Int [] g_bt = new int [smooth]; Int [] B _bt = new int [smooth]; Int [] gray_bt_src = new int [smooth]; Int [] r_bt_src = new int [smooth]; Int [] g_bt_src = new int [smooth]; Int [] B _bt_src = new int [smooth]; Int r, g, B; Int gray = 0, bt_index = 0, max = 0, maxindex = 0; I = 0; Bool frist = true; Int pos = 0; For (j = 0; j { If (frist) { For (int m =-radius; m <= radius; m ++) { For (int n =-radius; n <= radius; n ++) { Pos = Math. Abs (n) * unit + Math. Abs (m) * stride; B = srcValues [pos ++]; G = srcValues [pos ++]; R = srcValues [pos]; Gray = (B + g + r)/3; Bt_index = gray * smooth> 8; Gray_bt_src [bt_index] ++; B _bt_src [bt_index] + = B; G_bt_src [bt_index] + = g; R_bt_src [bt_index] + = r; } } Array. Copy (gray_bt_src, gray_bt, smooth ); Array. Copy (B _bt_src, B _bt, smooth ); Array. Copy (g_bt_src, g_bt, smooth ); Array. Copy (r_bt_src, r_bt, smooth ); Max = 0; Maxindex = 0; For (k = 0; k <smooth; k ++) { If (max <gray_bt [k]) { Max = gray_bt [k]; Maxindex = k; } } Pos = j * stride; TempValues [pos ++] = (byte) (B _bt [maxindex]/max ); TempValues [pos ++] = (byte) (g_bt [maxindex]/max ); TempValues [pos] = (byte) (r_bt [maxindex]/max ); Frist = false; } Else { For (int m =-radius; m <= radius; m ++) { Pos = Math. Abs (m) * unit + Math. Abs (j-radius-1) * stride; B = srcValues [pos ++]; G = srcValues [pos ++]; R = srcValues [pos]; Gray = (B + g + r)/3; Bt_index = gray * smooth> 8; Gray_bt_src [bt_index] --; B _bt_src [bt_index]-= B; G_bt_src [bt_index]-= g; R_bt_src [bt_index]-= r;
Pos = Math. Abs (m) * unit + Math. Abs (j + radius) % h * stride; B = srcValues [pos ++]; G = srcValues [pos ++]; R = srcValues [pos]; Gray = (B + g + r)/3; Bt_index = gray * smooth> 8; Gray_bt_src [bt_index] ++; B _bt_src [bt_index] + = B; G_bt_src [bt_index] + = g; R_bt_src [bt_index] + = r; } Array. Copy (gray_bt_src, gray_bt, smooth ); Array. Copy (B _bt_src, B _bt, smooth ); Array. Copy (g_bt_src, g_bt, smooth ); Array. Copy (r_bt_src, r_bt, smooth ); } For (I = 1; I <w; I ++) { For (int m =-radius; m <= radius; m ++) { Pos = Math. Abs (I-radius-1) * unit + Math. Abs (j + m) % h * stride; B = srcValues [pos ++]; G = srcValues [pos ++]; R = srcValues [pos]; Gray = (B + g + r)/3; Bt_index = gray * smooth> 8; Gray_bt [bt_index] --; B _bt [bt_index]-= B; G_bt [bt_index]-= g; R_bt [bt_index]-= r;
Pos = Math. Abs (I + radius) % w * unit + Math. Abs (j + m) % h * stride; B = srcValues [pos ++]; G = srcValues [pos ++]; R = srcValues [pos]; Gray = (B + g + r)/3; Bt_index = gray * smooth> 8; Gray_bt [bt_index] ++; B _bt [bt_index] + = B; G_bt [bt_index] + = g; R_bt [bt_index] + = r; } Max = 0; Maxindex = 0; For (k = 0; k <smooth; k ++) { If (max <gray_bt [k]) { Max = gray_bt [k]; Maxindex = k; } } Pos = I * unit + j * stride; TempValues [pos ++] = (byte) (B _bt [maxindex]/max ); TempValues [pos ++] = (byte) (g_bt [maxindex]/max ); TempValues [pos] = (byte) (r_bt [maxindex]/max ); } } SrcValues = (byte []) tempValues. Clone (); System. Runtime. InteropServices. Marshal. Copy (srcValues, 0, ptr, bytes ); A. UnlockBits (srcData ); Return; } As follows: Source image Watercolor Filter Finally, put a complete C # version of the DEMO: http://www.zealpixel.com/thread-61-1-1.html |