• 图像处理------简单脸谱检测算法 分类: 视频图像处理 2015-07-24 10:11 42人阅读 评论(0) 收藏


    介绍基于皮肤检测之后的,寻找最大连通区域,完成脸谱检测的算法。大致的算法步骤如下:


    原图如下:


    每步处理以后的效果:


    程序运行,加载选择图像以后的截屏如下:


    截屏中显示图片,是适当放缩以后,代码如下:

    1. Image scaledImage = rawImg.getScaledInstance(200200, Image.SCALE_FAST); // Java Image API, rawImage is source image  
    2. g2.drawImage(scaledImage, 00200200null);  

    第一步:图像预处理,预处理的目的是为了减少图像中干扰像素,使得皮肤检测步骤可以得

    到更好的效果,最常见的手段是调节对比度与亮度,也可以高斯模糊。

    这里调节对比度的算法很简单,源代码如下:

    1. package com.gloomyfish.face.detection;  
    2.   
    3. import java.awt.image.BufferedImage;  
    4.   
    5. public class ContrastFilter extends AbstractBufferedImageOp {  
    6.       
    7.     private double nContrast = 30;  
    8.       
    9.     public ContrastFilter() {  
    10.         System.out.println("Contrast Filter");  
    11.     }  
    12.   
    13.     @Override  
    14.     public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
    15.         int width = src.getWidth();  
    16.         int height = src.getHeight();  
    17.         double contrast = (100.0 + nContrast) / 100.0;  
    18.         contrast *= contrast;  
    19.         if ( dest == null )  
    20.             dest = createCompatibleDestImage( src, null );  
    21.   
    22.         int[] inPixels = new int[width*height];  
    23.         int[] outPixels = new int[width*height];  
    24.         getRGB( src, 00, width, height, inPixels );  
    25.         int index = 0;  
    26.         int ta = 0, tr = 0, tg = 0, tb = 0;  
    27.         for(int row=0; row<height; row++) {  
    28.             for(int col=0; col<width; col++) {  
    29.                 index = row * width + col;  
    30.                 ta = (inPixels[index] >> 24) & 0xff;  
    31.                 tr = (inPixels[index] >> 16) & 0xff;  
    32.                 tg = (inPixels[index] >> 8) & 0xff;  
    33.                 tb = inPixels[index] & 0xff;  
    34.                   
    35.                 // adjust contrast - red, green, blue  
    36.                 tr = adjustContrast(tr, contrast);  
    37.                 tg = adjustContrast(tg, contrast);  
    38.                 tb = adjustContrast(tb, contrast);  
    39.                   
    40.                 // output RGB pixel  
    41.                 outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;  
    42.             }  
    43.         }  
    44.         setRGB( dest, 00, width, height, outPixels );  
    45.         return dest;  
    46.     }  
    47.       
    48.     public int adjustContrast(int color, double contrast) {  
    49.         double result = 0;  
    50.         result = color / 255.0;  
    51.         result -= 0.5;  
    52.         result *= contrast;  
    53.         result += 0.5;  
    54.         result *=255.0;  
    55.         return clamp((int)result);  
    56.     }  
    57.       
    58.     public static int clamp(int c) {  
    59.         if (c < 0)  
    60.             return 0;  
    61.         if (c > 255)  
    62.             return 255;  
    63.         return c;  
    64.     }  
    65.   
    66. }  

    注意:第一步不是必须的,如果图像质量已经很好,可以直接跳过。


    第二步:皮肤检测,采用的是基于RGB色彩空间的统计结果来判断一个像素是否为skin像

    素,如果是皮肤像素,则设置像素为黑色,否则为白色。给出基于RGB色彩空间的五种皮

    肤检测统计方法,最喜欢的一种源代码如下:

    1. package com.gloomyfish.face.detection;  
    2.   
    3. import java.awt.image.BufferedImage;  
    4. /** 
    5.  * this skin detection is absolutely good skin classification, 
    6.  * i love this one very much 
    7.  *  
    8.  * this one should be always primary skin detection  
    9.  * from all five filters 
    10.  *  
    11.  * @author zhigang 
    12.  * 
    13.  */  
    14. public class SkinFilter4 extends AbstractBufferedImageOp {  
    15.   
    16.     @Override  
    17.     public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
    18.         int width = src.getWidth();  
    19.         int height = src.getHeight();  
    20.   
    21.         if ( dest == null )  
    22.             dest = createCompatibleDestImage( src, null );  
    23.   
    24.         int[] inPixels = new int[width*height];  
    25.         int[] outPixels = new int[width*height];  
    26.         getRGB( src, 00, width, height, inPixels );  
    27.         int index = 0;  
    28.         for(int row=0; row<height; row++) {  
    29.             int ta = 0, tr = 0, tg = 0, tb = 0;  
    30.             for(int col=0; col<width; col++) {  
    31.                 index = row * width + col;  
    32.                 ta = (inPixels[index] >> 24) & 0xff;  
    33.                 tr = (inPixels[index] >> 16) & 0xff;  
    34.                 tg = (inPixels[index] >> 8) & 0xff;  
    35.                 tb = inPixels[index] & 0xff;  
    36.                   
    37.                 // detect skin method...  
    38.                 double sum = tr + tg + tb;  
    39.                 if (((double)tb/(double)tg<1.249) &&  
    40.                     ((double)sum/(double)(3*tr)>0.696) &&  
    41.                     (0.3333-(double)tb/(double)sum>0.014) &&  
    42.                     ((double)tg/(double)(3*sum)<0.108))  
    43.                 {  
    44.                     tr = tg = tb = 0;  
    45.                 } else {  
    46.                     tr = tg = tb = 255;  
    47.                 }  
    48.                 outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;  
    49.             }  
    50.         }  
    51.         setRGB(dest, 00, width, height, outPixels);  
    52.         return dest;  
    53.     }  
    54. }  

    第三步:寻找最大连通区域

    使用连通组件标记算法,寻找最大连通区域,关于什么是连通组件标记算法,可以参见这里

    http://blog.csdn.net/jia20003/article/details/7483249,里面提到的连通组件算法效率不高,所

    以这里我完成了一个更具效率的版本,主要思想是对像素数据进行八邻域寻找连通,然后合

    并标记。源代码如下:

    1. package com.gloomyfish.face.detection;  
    2.   
    3. import java.util.Arrays;  
    4. import java.util.HashMap;  
    5.   
    6. /** 
    7.  * fast connected component label algorithm 
    8.  *  
    9.  * @date 2012-05-23 
    10.  * @author zhigang 
    11.  * 
    12.  */  
    13. public class FastConnectedComponentLabelAlg {  
    14.     private int bgColor;  
    15.     private int[] labels;  
    16.     private int[] outData;  
    17.     private int dw;  
    18.     private int dh;  
    19.       
    20.     public FastConnectedComponentLabelAlg() {  
    21.         bgColor = 255// black color  
    22.     }  
    23.   
    24.     public int[] doLabel(int[] inPixels, int width, int height) {  
    25.         dw = width;  
    26.         dh = height;  
    27.         int nextlabel = 1;  
    28.         int result = 0;  
    29.         labels = new int[dw * dh/2];  
    30.         outData = new int[dw * dh];  
    31.         for(int i=0; i<labels.length; i++) {  
    32.             labels[i] = i;  
    33.         }  
    34.           
    35.         // we need to define these two variable arrays.  
    36.         int[] fourNeighborhoodPixels = new int[8];  
    37.         int[] fourNeighborhoodLabels = new int[8];  
    38.         int[] knownLabels = new int[4];  
    39.           
    40.         int srcrgb = 0, index = 0;  
    41.         boolean existedLabel = false;  
    42.         for(int row = 0; row < height; row ++) {  
    43.             for(int col = 0; col < width; col++) {  
    44.                 index = row * width + col;  
    45.                 srcrgb = inPixels[index] & 0x000000ff;  
    46.                 if(srcrgb == bgColor) {  
    47.                     result = 0// which means no labeled for this pixel.  
    48.                 } else {  
    49.                     // we just find the eight neighborhood pixels.  
    50.                     fourNeighborhoodPixels[0] = getPixel(inPixels, row-1, col); // upper cell  
    51.                     fourNeighborhoodPixels[1] = getPixel(inPixels, row, col-1); // left cell  
    52.                     fourNeighborhoodPixels[2] = getPixel(inPixels, row+1, col); // bottom cell  
    53.                     fourNeighborhoodPixels[3] = getPixel(inPixels, row, col+1); // right cell  
    54.                       
    55.                     // four corners pixels  
    56.                     fourNeighborhoodPixels[4] = getPixel(inPixels, row-1, col-1); // upper left corner  
    57.                     fourNeighborhoodPixels[5] = getPixel(inPixels, row-1, col+1); // upper right corner  
    58.                     fourNeighborhoodPixels[6] = getPixel(inPixels, row+1, col-1); // left bottom corner  
    59.                     fourNeighborhoodPixels[7] = getPixel(inPixels, row+1, col+1); // right bottom corner  
    60.                       
    61.                     // get current possible existed labels  
    62.                     fourNeighborhoodLabels[0] = getLabel(outData, row-1, col); // upper cell  
    63.                     fourNeighborhoodLabels[1] = getLabel(outData, row, col-1); // left cell  
    64.                     fourNeighborhoodLabels[2] = getLabel(outData, row+1, col); // bottom cell  
    65.                     fourNeighborhoodLabels[3] = getLabel(outData, row, col+1); // right cell  
    66.                       
    67.                     // four corners labels value  
    68.                     fourNeighborhoodLabels[4] = getLabel(outData, row-1, col-1); // upper left corner  
    69.                     fourNeighborhoodLabels[5] = getLabel(outData, row-1, col+1); // upper right corner  
    70.                     fourNeighborhoodLabels[6] = getLabel(outData, row+1, col-1); // left bottom corner  
    71.                     fourNeighborhoodLabels[7] = getLabel(outData, row+1, col+1); // right bottom corner  
    72.                       
    73.                     knownLabels[0] = fourNeighborhoodLabels[0];  
    74.                     knownLabels[1] = fourNeighborhoodLabels[1];  
    75.                     knownLabels[2] = fourNeighborhoodLabels[4];  
    76.                     knownLabels[3] = fourNeighborhoodLabels[5];  
    77.                       
    78.                     existedLabel = false;  
    79.                     for(int k=0; k<fourNeighborhoodLabels.length; k++) {  
    80.                         if(fourNeighborhoodLabels[k] != 0) {  
    81.                             existedLabel = true;  
    82.                             break;  
    83.                         }  
    84.                     }  
    85.                       
    86.                     if(!existedLabel) {  
    87.                         result = nextlabel;  
    88.                         nextlabel++;  
    89.                     } else {  
    90.                         int found = -1, count = 0;  
    91.                         for(int i=0; i<fourNeighborhoodPixels.length; i++) {  
    92.                             if(fourNeighborhoodPixels[i] != bgColor) {  
    93.                                 found = i;  
    94.                                 count++;  
    95.                             }  
    96.                         }  
    97.                           
    98.                         if(count == 1) {  
    99.                             result = (fourNeighborhoodLabels[found] == 0) ? nextlabel : fourNeighborhoodLabels[found];  
    100.                         } else {  
    101.                             result = (fourNeighborhoodLabels[found] == 0) ? nextlabel : fourNeighborhoodLabels[found];  
    102.                             for(int j=0; j<knownLabels.length; j++) {  
    103.                                 if(knownLabels[j] != 0 && knownLabels[j] != result &&  
    104.                                         knownLabels[j] < result) {  
    105.                                     result = knownLabels[j];  
    106.                                 }  
    107.                             }  
    108.                               
    109.                             boolean needMerge = false;  
    110.                             for(int mm = 0; mm < knownLabels.length; mm++ ) {  
    111.                                 if(knownLabels[0] != knownLabels[mm] && knownLabels[mm] != 0) {  
    112.                                     needMerge = true;  
    113.                                 }  
    114.                             }  
    115.                               
    116.                             // merge the labels now....  
    117.                             if(needMerge) {  
    118.                                 int minLabel = knownLabels[0];  
    119.                                 for(int m=0; m<knownLabels.length; m++) {  
    120.                                     if(minLabel > knownLabels[m] && knownLabels[m] != 0) {  
    121.                                         minLabel = knownLabels[m];  
    122.                                     }  
    123.                                 }  
    124.                                   
    125.                                 // find the final label number...  
    126.                                 result = (minLabel == 0) ? result : minLabel;  
    127.                                           
    128.                                 // re-assign the label number now...  
    129.                                 if(knownLabels[0] != 0) {  
    130.                                     setData(outData, row-1, col, result);  
    131.                                 }  
    132.                                 if(knownLabels[1] != 0) {  
    133.                                     setData(outData, row, col-1, result);  
    134.                                 }  
    135.                                 if(knownLabels[2] != 0) {  
    136.                                     setData(outData, row-1, col-1, result);  
    137.                                 }  
    138.                                 if(knownLabels[3] != 0) {  
    139.                                     setData(outData, row-1, col+1, result);  
    140.                                 }  
    141.                                   
    142.                             }  
    143.                         }  
    144.                     }  
    145.                 }  
    146.                 outData[index] = result; // assign to label  
    147.             }  
    148.         }  
    149.           
    150.         // post merge each labels now  
    151.         for(int row = 0; row < height; row ++) {  
    152.             for(int col = 0; col < width; col++) {  
    153.                 index = row * width + col;  
    154.                 mergeLabels(index);  
    155.             }  
    156.         }  
    157.           
    158.         // labels statistic  
    159.         HashMap<Integer, Integer> labelMap = new HashMap<Integer, Integer>();  
    160.         for(int d=0; d<outData.length; d++) {  
    161.             if(outData[d] != 0) {  
    162.                 if(labelMap.containsKey(outData[d])) {  
    163.                     Integer count = labelMap.get(outData[d]);  
    164.                     count+=1;  
    165.                     labelMap.put(outData[d], count);  
    166.                 } else {  
    167.                     labelMap.put(outData[d], 1);  
    168.                 }  
    169.             }  
    170.         }  
    171.           
    172.         // try to find the max connected component  
    173.         Integer[] keys = labelMap.keySet().toArray(new Integer[0]);  
    174.         Arrays.sort(keys);  
    175.         int maxKey = 1;  
    176.         int max = 0;  
    177.         for(Integer key : keys) {  
    178.             if(max < labelMap.get(key)){  
    179.                 max = labelMap.get(key);  
    180.                 maxKey = key;  
    181.             }  
    182.             System.out.println( "Number of " + key + " = " + labelMap.get(key));  
    183.         }  
    184.         System.out.println("maxkey = " + maxKey);  
    185.         System.out.println("max connected component number = " + max);  
    186.         return outData;  
    187.     }  
    188.   
    189.     private void mergeLabels(int index) {  
    190.         int row = index / dw;  
    191.         int col = index % dw;  
    192.           
    193.         // get current possible existed labels  
    194.         int min = getLabel(outData, row, col);  
    195.         if(min == 0return;  
    196.         if(min > getLabel(outData, row-1, col) && getLabel(outData, row-1, col) != 0) {  
    197.             min = getLabel(outData, row-1, col);  
    198.         }  
    199.           
    200.         if(min > getLabel(outData, row, col-1) && getLabel(outData, row, col-1) != 0) {  
    201.             min = getLabel(outData, row, col-1);  
    202.         }  
    203.           
    204.         if(min > getLabel(outData, row+1, col) && getLabel(outData, row+1, col) != 0) {  
    205.             min = getLabel(outData, row+1, col);  
    206.         }  
    207.           
    208.         if(min > getLabel(outData, row, col+1) && getLabel(outData, row, col+1) != 0) {  
    209.             min = getLabel(outData, row, col+1);  
    210.         }  
    211.           
    212.         if(min > getLabel(outData, row-1, col-1) && getLabel(outData, row-1, col-1) != 0) {  
    213.             min = getLabel(outData, row-1, col-1);  
    214.         }  
    215.           
    216.         if(min > getLabel(outData, row-1, col+1) && getLabel(outData, row-1, col+1) != 0) {  
    217.             min = getLabel(outData, row-1, col+1);  
    218.         }  
    219.           
    220.         if(min > getLabel(outData, row+1, col-1) && getLabel(outData, row+1, col-1) != 0) {  
    221.             min = getLabel(outData, row+1, col-1);  
    222.         }  
    223.           
    224.         if(min > getLabel(outData, row+1, col+1) && getLabel(outData, row+1, col+1) != 0) {  
    225.             min = getLabel(outData, row+1, col+1);  
    226.         }  
    227.   
    228.         if(getLabel(outData, row, col) == min)  
    229.             return;  
    230.         outData[index] = min;  
    231.           
    232.         // eight neighborhood pixels  
    233.         if((row -1) >= 0) {  
    234.               
    235.             mergeLabels((row-1)*dw + col);  
    236.         }  
    237.           
    238.         if((col-1) >= 0) {  
    239.             mergeLabels(row*dw+col-1);  
    240.         }  
    241.           
    242.         if((row+1) < dh) {  
    243.             mergeLabels((row + 1)*dw+col);  
    244.         }  
    245.           
    246.         if((col+1) < dw) {  
    247.             mergeLabels((row)*dw+col+1);  
    248.         }  
    249.           
    250.         if((row-1)>= 0 && (col-1) >=0) {  
    251.             mergeLabels((row-1)*dw+col-1);  
    252.         }  
    253.           
    254.         if((row-1)>= 0 && (col+1) < dw) {  
    255.             mergeLabels((row-1)*dw+col+1);  
    256.         }  
    257.           
    258.         if((row+1) < dh && (col-1) >=0) {  
    259.             mergeLabels((row+1)*dw+col-1);  
    260.         }  
    261.           
    262.         if((row+1) < dh && (col+1) < dw) {  
    263.             mergeLabels((row+1)*dw+col+1);  
    264.         }  
    265.     }  
    266.       
    267.     private void setData(int[] data, int row, int col, int value) {  
    268.         if(row < 0 || row >= dh) {  
    269.             return;  
    270.         }  
    271.           
    272.         if(col < 0 || col >= dw) {  
    273.             return;  
    274.         }  
    275.           
    276.         int index = row * dw + col;  
    277.         data[index] = value;  
    278.     }  
    279.       
    280.     private int getLabel(int[] data, int row, int col) {  
    281.         // handle the edge pixels  
    282.         if(row < 0 || row >= dh) {  
    283.             return 0;  
    284.         }  
    285.           
    286.         if(col < 0 || col >= dw) {  
    287.             return 0;  
    288.         }  
    289.           
    290.         int index = row * dw + col;  
    291.         return (data[index] & 0x000000ff);  
    292.     }  
    293.   
    294.     private int getPixel(int[] data, int row, int col) {  
    295.         // handle the edge pixels  
    296.         if(row < 0 || row >= dh) {  
    297.             return bgColor;  
    298.         }  
    299.           
    300.         if(col < 0 || col >= dw) {  
    301.             return bgColor;  
    302.         }  
    303.           
    304.         int index = row * dw + col;  
    305.         return (data[index] & 0x000000ff);  
    306.     }  
    307.   
    308.     /** 
    309.      * binary image data: 
    310.      *  
    311.      * 255, 0,   0,   255,   0,   255, 255, 0,   255, 255, 255, 
    312.      * 255, 0,   0,   255,   0,   255, 255, 0,   0,   255, 0, 
    313.      * 255, 0,   0,   0,     255, 255, 255, 255, 255, 0,   0, 
    314.      * 255, 255, 0,   255,   255, 255, 0,   255, 0,   0,   255 
    315.      * 255, 255, 0,   0,     0,   0,   255, 0,   0,   0,   0 
    316.      *  
    317.      * height = 5, width = 11 
    318.      * @param args 
    319.      */  
    320.     public static int[] imageData = new int[]{  
    321.          2550,   0,   255,   0,   2552550,   255255255,  
    322.          2550,   0,   255,   0,   2552550,   0,   2550,  
    323.          2550,   0,   0,     2552552552552550,   0,  
    324.          2552550,   255,   2552550,   2550,   0,   255,  
    325.          2552550,   0,     0,   0,   2550,   0,   0,   0  
    326.     };  
    327.       
    328.     public static void main(String[] args) {  
    329.         FastConnectedComponentLabelAlg ccl = new FastConnectedComponentLabelAlg();  
    330.         int[] outData = ccl.doLabel(imageData, 115);  
    331.         for(int i=0; i<5; i++) {  
    332.             System.out.println("--------------------");  
    333.             for(int j = 0; j<11; j++) {  
    334.                 int index = i * 11 + j;  
    335.                 if(j != 0) {  
    336.                     System.out.print(",");  
    337.                 }  
    338.                 System.out.print(outData[index]);  
    339.             }  
    340.             System.out.println();  
    341.         }  
    342.     }  
    343.   
    344. }  

    找到最大连通区域以后,对最大连通区域数据进行扫描,找出最小点,即矩形区域左上角坐

    标,找出最大点,即矩形区域右下角坐标。知道这四个点坐标以后,在原图上打上红色矩形

    框,标记出脸谱位置。寻找四个点坐标的实现代码如下:

    1. private void getFaceRectangel() {  
    2.     int width = resultImage.getWidth();  
    3.        int height = resultImage.getHeight();  
    4.        int[] inPixels = new int[width*height];  
    5.        getRGB(resultImage, 00, width, height, inPixels);  
    6.          
    7.        int index = 0;  
    8.        int ta = 0, tr = 0, tg = 0, tb = 0;  
    9.        for(int row=0; row<height; row++) {  
    10.         for(int col=0; col<width; col++) {  
    11.             index = row * width + col;  
    12.             ta = (inPixels[index] >> 24) & 0xff;  
    13.                tr = (inPixels[index] >> 16) & 0xff;  
    14.                tg = (inPixels[index] >> 8) & 0xff;  
    15.                tb = inPixels[index] & 0xff;  
    16.                if(tr == tg && tg == tb && tb == 0) { // face skin  
    17.                 if(minY > row) {  
    18.                     minY = row;  
    19.                 }  
    20.                   
    21.                 if(minX > col) {  
    22.                     minX = col;  
    23.                 }  
    24.                   
    25.                 if(maxY < row) {  
    26.                     maxY = row;  
    27.                 }  
    28.                   
    29.                 if(maxX < col) {  
    30.                     maxX = col;  
    31.                 }  
    32.                }  
    33.         }  
    34.        }  
    35. }  
    缺点:

    此算法不支持多脸谱检测,不支持裸体中的脸谱检测,但是根据人脸的

    生物学特征可以进一步细化分析,支持裸体人脸检测

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    nfs只能挂载为nobody的解决方法
    Mysql一些记忆
    shell中交互输入自动化
    关闭SElinux
    《Windows核心编程系列》十谈谈同步设备IO与异步设备IO之异步IO
    《Windows核心编程系列》九谈谈同步设备IO与异步设备IO之同步设备IO
    《Windows核心编程系列》八谈谈用内核对象进行线程同步
    《windows核心编程系列》七谈谈用户模式下的线程同步
    《windows核心编程系列 》六谈谈线程调度、优先级和关联性
    《windows核心编程系列》五谈谈线程基础
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706358.html
Copyright © 2020-2023  润新知