2018-08-29 00:37:44 hfutdog 阅读数 7794

最近开始接触图像处理,接到的首个任务就是将实验室用颜色标记好的数据再在原图上按不同颜色框出来,以在模型预测阶段检查预测效果。下面使用一张摇滚乐队Halestrom的图片进行说明。

首先,我拿到的原图如下图所示:

图1

我们将原始图片按照人、地板、墙三种元素进行标记,得到下图:

图2

将上述两张图片输入我们的模型,那么模型能够做到给出一张新的图片它就能够输出一张按颜色分类标记元素的图片。我们这里要做的是,将按颜色分类标记元素的区块转换为线框绘制在原始图片上,便于检测预测效果,具体需要得到的图片如下图所示:

图3

这就需要我们根据颜色分辨出图2中的区域,然后在原图上对其描框,具体实现可以参考以下代码:

"""功能:检测图像颜色按区块划分边框"""

import numpy as np
import cv2
import os


def detect_color(img_path, mark_img_path):
    """检测一张图片中的不同颜色区域"""
    image = cv2.imread(img_path)  # 加载图片
    # 定义颜色范围,这里可以根据自己的需求定义,注意这里颜色定义的顺序是BGR
    boundaries = [
        ([0, 0, 255], [0, 0, 255]),  # 红色
        ([0, 255, 0], [0, 255, 0]),  # 绿色
        ([255, 0, 0], [255, 0, 0])  # 蓝色
    ]

    # 遍历颜色范围
    for (lower, upper) in boundaries:
        # 由颜色范围创建NumPy数组
        lower = np.array(lower, dtype="uint8")
        upper = np.array(upper, dtype="uint8")

        # 根据特定颜色范围创建mask
        mask = cv2.inRange(image, lower, upper)
        output = cv2.bitwise_and(image, image, mask=mask)

        mark_zone_with_color(output, mark_img_path, lower)


def mark_zone_with_color(src_img, mark_img, mark_color):
    """根据颜色在原始图像上标记区域"""
    # 转灰度图片
    gray = cv2.cvtColor(src_img, cv2.COLOR_BGR2GRAY)

    ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)  # ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) 则只能绘制出平地轮廓

    # 轮廓检测
    _, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

    newImg = cv2.imread(mark_img)
    newImg = cv2.resize(newImg, (512, 512))
    # 画图
    for i in range(len(contours)-1):
        cv2.drawContours(image=newImg, contours=contours[i+1], contourIdx=-1, color=tuple(mark_color.tolist()), thickness=2, maxLevel=1, lineType=8)

    cv2.imwrite(mark_img, newImg)


def batch_marker(src_img_dir, draw_contours_img_dir):
    """
    批处理需要标记的图像,注意这里默认原始图像和标记了颜色区块的图像
    是同名的,但是放在不同的文件夹里。
    """
    src_imgs = get_filenames_in_dir(src_img_dir)
    dc_imgs = get_filenames_in_dir(draw_contours_img_dir)

    for src in src_imgs:
        for dc in dc_imgs:
            if src == dc:
                detect_color(os.path.join(src_img_dir, src), os.path.join(draw_contours_img_dir, dc))


def get_filenames_in_dir(dir):
    """获取一个目录下所有文件的文件名"""
    for root, dirs, files in os.walk(dir):
        return files

使用时直接调用detect_color函数就可以了,第一个参数是像图2一样的图片路径,第二个参数是像图1一样的原始图片的路径。

opencv是经常会被使用到的图像处理库,下面介绍一下上述代码中使用到的几个关键函数。

inRange(src, lowerb, upperb[, dst]) -> dst

参数含义:src:输入源图像。

         lowrb:需要检测图像像素范围的下阈值。

         upperb:需要检测图像像素范围的上阈值。

         dst:输出图像数组,形状和输入图像src一致,CV_8U类型。

功能:将图像中的像素在lowrb和upperrb范围内的设置成255,范围之外的设置成0以输出。
cvtColor(src, code[, dst[, dstCn]]) -> dst

参数含义:src:输入源图像。

         code:图像编码方式或者是颜色空间。

功能:将图像从一个颜色空间转换到另外一个颜色空间,通常是将BGR图像转换为灰度图。
threshold(src, thresh, maxval, type[, dst]) -> retval, dst

参数含义:src:输入源图像。

         thresh:阈值。

         maxval:用于THRESH_BINARY和THRESH_BINARY_INV阈值处理的最大值。

         type:阈值类型。

         dst:与输入源图像src具有相同大小、类型、通道数的图像。

功能:通常用于从灰度图中获取二进制图像或者用于去除图像噪声(即去除太大或太小的像素)。
findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> image, contours, hierarchy

参数含义:image:输入源图像,一个8位单通道图像,非零像素被视为1,零像素保持为0,即二进制图像。如果 
         mode等于RETR_CCOMP或RETR_FLOODFILL,则输入也可以是32位整数图像标签。

         mode:轮廓检索模式。

         method:轮廓逼近方法。

         contours:检测到的轮廓,每个轮廓被存为点的矢量。

         hierarchy:可选的输出矢量。包含图像的拓扑信息,具有和轮廓相同数量的元素。

         offset:每个轮廓点的可选偏移量。

功能:从二进制图像中检索轮廓。轮廓是用于形状分析和物体检测识别的常用工具。
drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> image

参数含义:image:目标图片。

         contours:所有输入轮廓,每个轮廓都被存储为点的矢量。

         contourIdx:要绘制的轮廓的索引,如果为-1则绘制所有的轮廓。

         color:轮廓绘制采用的颜色。

         thickness:要绘制轮廓的线条的粗细,如果是负的,则绘制轮廓内线条。

         lineType:线路连接。

         hierarchy:需要绘制的轮廓的层次信息。仅当只需要绘制部分轮廓时这个参数才有用。

         maxLevel:绘制轮廓的最大级别。如果为0,则绘制指定的轮廓;如果为1,则绘制所有轮廓(含嵌套 
         轮廓);如果是2,那么绘制所有轮廓,包括嵌套轮廓,嵌套的嵌套轮廓等等,但只有当有可用的层次 
         结构时参数才有效。

         offset:可选的轮廓位移参数。

功能:绘制轮廓或填充轮廓。

好了,整个代码其实比较简单,主要是调用了上面几个函数。如果朋友们还有什么函数不清楚的可以自行查看文档。若对上述代码有疑问或建议的可以评论留言给我,以使我不断给大家提供更好的代码及博文。在此提前谢过,感谢朋友们的阅读!

 

2015-12-26 10:30:38 wp1603710463 阅读数 1409

                 Matlab图像处理函数汇总

1.图像的变换:

   ① fft2:fft2函数用于数字图像的二维傅立叶变换,如:
     i=imread('104_8.tif');
     j=fft2(i);</span>

   ② ifft2: ifft2函数用于数字图像的二维傅立叶反变换,如:

     i=imread('104_8.tif');
     j=fft2(i);
     k=ifft2(j);</span>

2.模拟噪声生成函数和预定义滤波器:

   ① imnoise:用于对图像生成模拟噪声,如:

     i=imread('104_8.tif');
     j=imnoise(i,'gaussian',0,0.02); %模拟高斯噪声</span>

   ② fspecial:用于产生预定义滤波器,如:

     h=fspecial('sobel');     %sobel水平边缘增强滤波器
     h=fspecial('gaussian');   %高斯低通滤波器
     h=fspecial('laplacian');   %拉普拉斯滤波器
     h=fspecial('log');         %高斯拉普拉斯(LoG)滤波器
     h=fspecial('average');     %均值滤波器</span>

3.图像的增强:

   ①直方图:imhist函数用于数字图像的直方图显示,如:

    i=imread('104_8.tif');
    imhist(i);</span>

   ②直方图均化:histeq函数用于数字图像的直方图均化,如:

     i=imread('104_8.tif');
     j=histeq(i);</span>

   ③对比度调整:imadjust函数用于数字图像的对比度调整,如:

          i=imread('104_8.tif');
          j=imadjust(i,[0.3,0.7],[]);</span></span>

   ④对数变换:log函数用于数字图像的对数变换,如:

     i=imread('104_8.tif');
     j=double(i);
     k=log(j);</span>

   ⑤基于卷积的图像滤波函数:filter2函数用于图像滤波,如:

     i=imread('104_8.tif');
     h=[1,2,1;0,0,0;-1,-2,-1];
     j=filter2(h,i);</span>

   ⑥线性滤波:利用二维卷积conv2滤波, 如:

      i=imread('104_8.tif');
      h=[1,1,1;1,1,1;1,1,1];
      h=h/9;
      j=conv2(i,h);</span>
   ⑦中值滤波:medfilt2函数用于图像的中值滤波,如:

     i=imread('104_8.tif');
     j=medfilt2(i);</span>

   ⑧锐化

   (1)利用Sobel算子锐化图像, 如:

    i=imread('104_8.tif');
    h=[1,2,1;0,0,0;-1,-2,-1];   %Sobel算子
    j=filter2(h,i);</span>
   (2)利用拉氏算子锐化图像, 如:

    i=imread('104_8.tif');
    j=double(i);
    h=[0,1,0;1,-4,0;0,1,0];  %拉氏算子
    k=conv2(j,h,'same');
    m=j-k;</span>

4.图像边缘检测:

   ① sobel算子 如:

    i = imread('104_8.tif');
    j = edge(i,'sobel',thresh);</span>
   ② prewitt算子 如:

    i = imread('104_8.tif');
    j = edge(i,'prewitt',thresh);</span>
   ③roberts算子  如:

    i=imread('104_8.tif');
    j =edge(i,'roberts',thresh);</span>

   ④log算子  如:

   i=imread('104_8.tif');
    j =edge(i,'log',thresh);</span>

   ⑤canny算子 如:

    i=imread('104_8.tif');
    j =edge(i,'canny',thresh);</span>

   ⑥Zero-Cross算子 如:

    i=imread('104_8.tif');
    j =edge(i,'zerocross',thresh);</span>

5.形态学图像处理:

   ①膨胀:是在二值化图像中“加长”或“变粗”的操作,函数imdilate执行膨胀运算,如:

    a=imread('104_7.tif');  %输入二值图像
    b=[0 1 0;1 1 1;01 0];
    c=imdilate(a,b);</span>
     ②腐蚀:函数imerode执行腐蚀,如:

    a=imread('104_7.tif');   %输入二值图像
    b=strel('disk',1);
    c=imerode(a,b);</span>

   ③开运算:先腐蚀后膨胀称为开运算,用imopen来实现,如:

   a=imread('104_8.tif');
   b=strel('square',2);
   c=imopen(a,b);</span>

   ④闭运算:先膨胀后腐蚀称为闭运算,用imclose来实现,如:

   a=imread('104_8.tif');
    b=strel('square',2);
    c=imclose(a,b);</span>

6.改变MATLAB背景颜色:

% 不使用MATLAB首选项中的配色
com.mathworks.services.Prefs.setBooleanPref('ColorsUseSystem',0);
% 指定背景颜色
com.mathworks.services.Prefs.setColorPref('ColorsBackground',java.awt.Color.green);
com.mathworks.services.ColorPrefs.notifyColorListeners('ColorsBackground');
cmdWinDoc = com.mathworks.mde.cmdwin.CmdWinDocument.getInstance;
listeners = cmdWinDoc.getDocumentListeners;
ii=1;
% 循环的方式,找到jTextArea的实例,然后设置颜色
while true
    jTextArea = listeners(ii);
    if isa(jTextArea,'javax.swing.JTextArea$AccessibleJTextArea')
        break
    end
    ii=ii+1;
end
% 可以使用下面任意一种方法设置背景色
jTextArea.setBackground(java.awt.Color.green);
jTextArea.setBackground(java.awt.Color(0,1,0));
set(jTextArea,'Background','green');
set(jTextArea,'Background',[0,1,0]);</span>

7.小波变换:

   ① 使用小波工具箱:

    wfilters:得到分解滤波器;

    wavedec2:分解等级函数,得到变换系数;

    waverec2:得到重构滤波器。

   ② 不使用小波工具箱:

    wavefiler:代替wfilters;

    wavefast:代替wavedec2;

    wavework:处理C(有三个使用wavework功能类似函数:wavecut,wavecopy,wavepaste);

    wave2gray:显示变换系数;

    waveback:代替waverec2。



2017-05-13 11:29:28 qq_18218335 阅读数 437

数字图像处理----行人检测

行人检测概述

目前行人检测方法主要分为两类

1.基于背景建模:利用背景建模方法,提取处前景运动的目标,在目标区域内进行特征提取,然后利用分类器进行分类,判断是否包含行人。

2.基于统计学的方法:根据大量的样本构建行人检测分类器。提取的特征主要有目标的灰度、边缘、纹理、颜色、梯度直方图等信息。分类器主要包括神经网络、SVM、adaboost 以及深度学习。

另外,目前的行人检测基本上都是基于法国研究人员Dalal在2005的CVPR发表的HOG+SVM的行人检测算法(Histograms of Oriented Gradients for Human Detection, Navneet Dalel,Bill Triggs, CVPR2005)

我们小组选择的就是上述HOG+SVM 的方法。

HOG 和 SVM 的简单介绍

机器学习中,支持向量机(英语:Support Vector Machine,常简称为SVM,又名支持向量网络[1])是在分类回归分析中分析数据的监督式学习模型与相关的学习算法。给定一组训练实例,每个训练实例被标记为属于两个类别中的一个或另一个,SVM训练算法创建一个将新的实例分配给两个类别之一的模型,使其成为非概率二元线性分类器。SVM模型是将实例表示为空间中的点,这样映射就使得单独类别的实例被尽可能宽的明显的间隔分开。然后,将新的实例映射到同一空间,并基于它们落在间隔的哪一侧来预测所属类别。

上述内容来自维基百科-------https://zh.wikipedia.org/wiki/%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%9C%BA-------------------------------

通俗的讲,我们将大量的已经标注类别的数据(我们使用的时候就是行人/非行人两类)交给SVM训练,只要样本数据能够较好的体现两类数据的区别,在训练好SVM之后,我们输入未知分类的数据,SVM就可以比较准确的给出我们此数据的类别(是否包含行人)

 

方向梯度直方图英语:Histogram of oriented gradient,简称HOG)是应用在计算机视觉图像处理领域,用于目标检测的特征描述器。这项技术是用来计算局部图像梯度的方向信息的统计值。HOG描述器是在一个网格密集的大小统一的细胞单元(dense grid of uniformly spaced cells)上计算,而且为了提高性能,还采用了重叠的局部对比度归一化(overlapping local contrast normalization)技术。

上述内容来自维基百科-------https://zh.wikipedia.org/wiki/%E6%96%B9%E5%90%91%E6%A2%AF%E5%BA%A6%E7%9B%B4%E6%96%B9%E5%9B%BE-

翻译成比较容易理解的话就是:图像中物体的局部外观和形状能够通过其局部梯度或边缘信息很好地表征和描述,即HOG可以描述图像中物体的局部外观和形状。结合上面的SVM,我们可以通过HOG提取大量的图片的特征信息,并标注图片是否有行人,以及行人的位置,并交给SVM训练。在大量数据的训练之后,SVM就可以区分行人。

HOG算法实现

假设识别窗口大小为:(winSize.width,winSize.height)。HOG将梯度方向(0—>360°)划分为nbins个区间。然后设置一个block其大小为(blockSize.width,blockSize.height),每个block分为许多cell(cellSize.width,cellSize.height)。对每个cell,算出每一点的梯度方向和模,按梯度方向增加每个bin 的值,形成每个cell 的梯度直方图。cell串联成块,块内归一化直方图,消除光照阴影的映像。block是在图像中边移动边计算的,其移动的方向为:从上到下,从左到右。步长blockStride为(blockStride.width,blockStride.height)。有了每个block的梯度直方图之后,然后多个block内的直方图向量一起串联成一个大的HOG特征向量。这个向量的大小如下面的公式:

nbins*

(blockSize.width/cellSize.width)*

(blockSize.height/cellSize.height)*

((winSize.width-blockSize.width)/blockStride.width+1)*

((winSize.height-blockSize.height)/blockStride.height+1);

即梯度方向数*每个block包含的cell 的个数*(水平方向移动次数+1)*(垂直方向移动次数+1)

对于opencv 中的实现,该值为:9*(16/8)*(16/8)*((64-16)/8+1)*(128-16)/8+1))=3780。这就是这个窗口对应的特征了。

结合图片便于理解

窗口大小

块大小 blockSize

cell大小

  • 梯度计算

    梯度算子:水平边缘算子: [-1, 0, 1] ;垂直边缘算子: [-1, 0, 1]T 

 

    图像中像素点(x,y)的梯度为:

作者测试后发现模板越简单效果越好,因此HOG 的梯度计算就是这么简单。

  • 直方图统计的方向单元划分

所谓的梯度直方图,就是一块区域的各个梯度方向的直方图。这里有一个选择就是梯度方向个数的选取,作者测试后发现把方向分为9个通道效果最好。另外,每个块的形状可以是矩形或圆形的,梯度直方图的方向取值可以是0-180°或者0-360°,取决于梯度是否有正负。

  • HOG描述器中的区块block

为了克服光照不均匀以及前景和背景的对比差异,梯度直方图必须归一化。HOG的做法是将连接在一起的cell串联到一起组成block,然后block内进行归一化。HOG描述器是block 在前面描述的识别窗口内边移动(原论文中移动步长一般为block 大小的一半)边计算并串联起来得到的。因此这些block通常会重叠,每个方格不只一次影响了最后的描述器,这样会有信息的冗余,但是能提高算法的精确度。主要有两种block。矩形R-HOG,原形C-HOG。我们选择矩形R-HOG,R-HOG由三个参数表示:每个block多少cell、每个cell有几个像素、每个通道有几个通道。在作者的测试中,发现当block size过大或者过小,对于局部图像的适应能力将会减弱 。block 内 cell 的个数为 3*3 或者2*2 的时候会有性能提升,另外,cell大小为6*6 ~ 8*8 的时候识别率比较好。这就有一个问题,就是应该如何选择cell 大小和block 大小,作者给出的答案是,使用特征选择机制如(AdaBoost)来帮助我们选择参数,而不是手动现实编码。这里我们取cell 8*8,block 2*2 cell

  • 为每个cell构建梯度方向直方图

这一步是为了统计局部图像梯度信息然后进行量化,得到局部图像区域的特征描述向量,同时能够保持对图像中人体对象的姿势和外观的若敏感性。

我们采用9个bin的直方图来统计这8*8 个像素的梯度信息。也就是将cell 的梯度方向360°分成9个方向块。这样梯度方向与bin有对应关系如下:

1 [0,40)
2 [40,80)
3 [80,120)
4 [120,160)
5 [160,200)
6 [200,240)
7 [240,280)
8 [280,320)
9 [320,0)

这样就可以得到这个cell 的梯度方向直方图了,就是该cell 对应的9维特征向量(因为有9个)。另外,这里直方图的大小就是梯度的大小,作者测试后这样的效果最好,不用另外进行直方图与梯度大小的代数变换。

  • 把cell组合成大的块(block),块内归一化梯度直方图

由于局部光照的变化以及前景-背景对比度的变化,使得梯度强度的变化范围非常大,需要对梯度强度做归一化。归一化能够进一步对光照、阴影和边缘进行压缩。

  1. 将多个临近的cell组成一个block块,然后对其梯度方向直方图向量

  2. 采用L2-Norm with Hysteresis threshold 方式进行归一化,即将直方图向量中横坐标最大值限制为0.2 一下,然后再重新归一化依次。

一个cell 会被多个block“共享”,另外,每个“cell”在被归一化时都是“block”无关的,每个cell 在其所属的block 中都会被归一化依次,得到一个vector。每个cell 的特征会议不同的结果多次出现在最后的特征向量中。

  • 归一化以及四种归一化方法的介绍

Dalal和Triggs采用了四种不同的方法对区间进行归一化,并对结果进行了比较。引入image表示一个还没有被归一化的向量,它包含了给定区间(block)的所有直方图信息。image 表示 imagek 阶范数,这里的image。用 image 表示一个很小的常数。这时,归一化因子可以表示如下:

image

  还有第四种归一化方式:L2-Hys,它可以通过先进行L2-norm,对结果进行截短(clipping),就是将直方图的最大值限制到0.2,然后再重新归一化得到。

作者发现:采用L2-Hys, L2-norm, 和 L1-sqrt方式所取得的效果是一样的,L1-norm稍微表现出一点点不可靠性。但是对于没有被归一化的数据来说,这四种方法都表现出来显著的改进

其中范数的概念如下:

$L$)X]1P]CLGRFB_1CM$6TV

  • 生成HOG特征描述向量

这一步相对比较简单,将所有归一化后的block 梯度直方图串联起来就形成了最后的HOG特征描述向量。

 

 

参考链接

http://blog.csdn.net/ttransposition/article/details/11880425

http://blog.csdn.net/ttransposition/article/details/41805767

http://blog.csdn.net/ttransposition/article/details/11874285

http://blog.csdn.net/zhazhiqiang/article/details/21047207

http://blog.csdn.net/qianqing13579/article/details/46509037

http://blog.csdn.net/carson2005/article/details/7841443

https://zh.wikipedia.org/wiki/%E6%96%B9%E5%90%91%E6%A2%AF%E5%BA%A6%E7%9B%B4%E6%96%B9%E5%9B%BE#.E6.8F.8F.E8.BF.B0.E5.99.A8.E5.8D.80.E5.A1.8A

http://www.cnblogs.com/lxy2017/p/3926760.html

http://blog.csdn.net/abcjennifer/article/details/7365651

2015-07-24 09:56:21 mao0514 阅读数 1975

基于像素的皮肤检测技术

介绍一种基于颜色空间的皮肤检测技术,可以检测亚洲人种与白人的皮肤,皮肤检测

人脸识别的基础,也是很多人像识别技术的基础操作,在实际应用中还是非常有用的。

 

基于像素的皮肤检测主要是寻找正确的颜色空间几何,图像处理中,常见的颜色空间

有如下几种

1.      RGB色彩空间 – R代表单色红,G代表单色绿,B代表单色蓝

2.      HSV色彩空间 – H 代表色彩, S代表饱和度,V代表强度值

3.      YCbCr色彩空间 – 是数字电视的色彩空间

 

RGB转换为HSV的Java代码如下:

  1. public static float[] rgbToHSV(int tr, int tg, int tb) {  
  2.     float min, max, delta;  
  3.     float hue, satur, value;  
  4.     min = Math.min(tr, Math.min(tg, tb));  
  5.     max = Math.max(tr, Math.max(tg, tb));  
  6.     value = max;  
  7.     delta = max - min;  
  8.     if(max != 0) {  
  9.         satur = delta/max;  
  10.     } else {  
  11.         satur = 0;  
  12.         hue = -1;  
  13.     }  
  14.       
  15.     if(tr == max) {  
  16.         hue = (tg - tb)/delta;  
  17.     }  
  18.     else if(tg == max) {  
  19.         hue = 2 + (tb-tr)/delta;  
  20.     } else {  
  21.         hue = 4 + (tr-tg)/delta;  
  22.     }  
  23.     hue = hue * 60.0f;  
  24.     if(hue < 0) {  
  25.         hue = hue + 360;  
  26.     }  
  27.     return new float[]{hue, satur, value};  
  28. }  

RGB转换为YCbCr的Java代码如下:

  1. public static int[] rgbToYcrCb(int tr, int tg, int tb) {  
  2.     double sum = tr + tg + tb;  
  3.     double r = ((double)tr)/sum;  
  4.     double g = ((double)tg)/sum;  
  5.     double b = ((double)tb)/sum;  
  6.     double y = 65.481 * r + 128.553 * g + 24.966 * b + 16.0d;  
  7.     double Cr = -37.7745 * r - 74.1592 * g + 111.9337 * b + 128.0d;  
  8.     double Cb = 111.9581 * r -93.7509 * g -18.2072 * b + 128.0d;  
  9.     return new int[]{(int)y, (int)Cr, (int)Cb};  
  10. }  
一个简单的基于RGB颜色空间的皮肤算法如下:

(R, G, B) is classified as skin if

R > 95 and G > 40 and B > 20and max{R, G, B} – min{R, G, B} > 15 and |R-G| > 15

and R > G and R > B

实现代码如下:

  1. public boolean isSkin(int tr, int tg, int tb) {  
  2.     int max = Math.max(tr, Math.max(tg, tb));  
  3.     int min = Math.min(tr, Math.min(tg, tb));  
  4.     int rg = Math.abs(tr - tg);  
  5.     if(tr > 95 && tg > 40 && tb > 20 && rg > 15 &&   
  6.             (max - min) > 15 && tr > tg && tr > tb) {  
  7.         return true;  
  8.     } else {  
  9.         return false;  
  10.     }  
  11. }  

一个简单的基于HSV颜色空间的皮肤算法如下:

(H, S, V) will be classified as skin if

H > 0 and H < 50 and S > 0.23 andS < 0.68

实现代码如下:

  1. public boolean isSkin(int tr, int tg, int tb) {  
  2.     float[] HSV = ColorUtil.rgbToHSV(tr, tg, tb);  
  3.     if((HSV[0] > 0.0f && HSV[0] < 50.0f ) && (HSV[1] > 0.23f && HSV[1] < 0.68f)){  
  4.         return true;  
  5.     } else {  
  6.         return false;  
  7.     }  
  8. }  

一个简单的基于YCbCr颜色空间的皮肤算法如下:

(Y, Cb, Cr) will be classified as skin if:

> 80 and 85<Cb < 135 and 135 <Cr < 180, and (Y,Cb,Cr)= [0,255] 

对于的Java代码如下:

  1. public boolean isSkin(int tr, int tg, int tb) {  
  2.     int y = (int)(tr * 0.299 + tg * 0.587 + tb * 0.114);  
  3.     int Cr = tr - y;  
  4.     int Cb = tb - y;  
  5.     if(y> 80 && y < 255 && Cr > 133 && Cr < 173 && 77 < Cb && Cb < 127) {  
  6.         return true;  
  7.     }  
  8.     return false;  
  9. }  
基于上述三个算法实现的皮肤检测的效果如下:


皮肤检测滤镜的源代码如下:

  1. package com.process.blur.study;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.image.BufferedImage;  
  5.   
  6. import com.gloomyfish.skin.dection.DefaultSkinDetection;  
  7. import com.gloomyfish.skin.dection.FastSkinDetection;  
  8. import com.gloomyfish.skin.dection.GaussianSkinDetection;  
  9. import com.gloomyfish.skin.dection.HSVSkinDetection;  
  10. import com.gloomyfish.skin.dection.ISkinDetection;  
  11.   
  12. public class SkinFilter extends AbstractBufferedImageOp {  
  13.     private ISkinDetection skinDetector;  
  14.       
  15.     public SkinFilter(int type) {  
  16.         if(type == 2) {  
  17.             skinDetector = new FastSkinDetection();  
  18.         } else if(type == 4) {  
  19.             skinDetector = new HSVSkinDetection();  
  20.         } else if(type == 8) {  
  21.             skinDetector = new GaussianSkinDetection();  
  22.         } else {  
  23.             skinDetector = new DefaultSkinDetection();  
  24.         }  
  25.     }  
  26.   
  27.     @Override  
  28.     public BufferedImage filter(BufferedImage src, BufferedImage dst) {  
  29.         int width = src.getWidth();  
  30.         int height = src.getHeight();  
  31.   
  32.         if ( dst == null )  
  33.             dst = createCompatibleDestImage( src, null );  
  34.   
  35.         int[] inPixels = new int[width*height];  
  36.         int[] outPixels = new int[width*height];  
  37.         getRGB( src, 00, width, height, inPixels );  
  38.         if(skinDetector instanceof GaussianSkinDetection) {  
  39.             ((GaussianSkinDetection)skinDetector).setDispSample(getDispersion(src));  
  40.         }  
  41.         int index = 0;  
  42.         for(int row=0; row<height; row++) {  
  43.             int ta = 0, tr = 0, tg = 0, tb = 0;  
  44.             for(int col=0; col<width; col++) {  
  45.                 index = row * width + col;  
  46.                 ta = (inPixels[index] >> 24) & 0xff;  
  47.                 tr = (inPixels[index] >> 16) & 0xff;  
  48.                 tg = (inPixels[index] >> 8) & 0xff;  
  49.                 tb = inPixels[index] & 0xff;  
  50.                 if(skinDetector.isSkin(tr, tg, tb)) {  
  51.                     outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;  
  52.                 } else {  
  53.                     tr = tg = tb = 0;  
  54.                     outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;  
  55.                 }                 
  56.             }  
  57.         }  
  58.         setRGB( dst, 00, width, height, outPixels );  
  59.         return dst;  
  60.     }  
  61.       
  62.     public Color getDispersion(BufferedImage image) {  
  63.         // calculate means of pixel    
  64.         int index = 0;  
  65.         int height = image.getHeight();  
  66.         int width = image.getWidth();  
  67.         int[] inPixels = new int[width*height];  
  68.         getRGB(image, 00, width, height, inPixels );  
  69.         double redSum = 0, greenSum = 0, blueSum = 0;  
  70.         Color meanColor = getMean(image);  
  71.         double redmeans = meanColor.getRed();  
  72.         double greenmeans = meanColor.getGreen();  
  73.         double bluemeans = meanColor.getBlue();  
  74.         double total = height * width;    
  75.         for(int row=0; row<height; row++) {    
  76.             int ta = 0, tr = 0, tg = 0, tb = 0;    
  77.             for(int col=0; col<width; col++) {    
  78.                 index = row * width + col;    
  79.                 ta = (inPixels[index] >> 24) & 0xff;    
  80.                 tr = (inPixels[index] >> 16) & 0xff;    
  81.                 tg = (inPixels[index] >> 8) & 0xff;    
  82.                 tb = inPixels[index] & 0xff;   
  83.                 double rd = (tr - redmeans);  
  84.                 double gd = (tg - greenmeans);  
  85.                 double bd = (tb - bluemeans);  
  86.                 redSum += rd * rd;    
  87.                 greenSum += gd * gd;    
  88.                 blueSum += bd * bd;    
  89.             }    
  90.         }  
  91.         int reddiff = (int)Math.sqrt((redSum / total));  
  92.         int greendiff = (int)Math.sqrt((greenSum / total));  
  93.         int bluediff = (int)Math.sqrt(blueSum / total);  
  94.         System.out.println(" red dispersion value = " + reddiff);  
  95.         System.out.println(" green dispersion value = " + greendiff);  
  96.         System.out.println(" blue dispersion value = " + bluediff);  
  97.         return new Color(reddiff, greendiff, bluediff);  
  98.     }  
  99.       
  100.     public Color getMean(BufferedImage image) {  
  101.         // calculate means of pixel    
  102.         int index = 0;  
  103.         int height = image.getHeight();  
  104.         int width = image.getWidth();  
  105.         int[] inPixels = new int[width*height];  
  106.         getRGB(image, 00, width, height, inPixels );  
  107.         double redSum = 0, greenSum = 0, blueSum = 0;    
  108.         double total = height * width;    
  109.         for(int row=0; row<height; row++) {    
  110.             int ta = 0, tr = 0, tg = 0, tb = 0;    
  111.             for(int col=0; col<width; col++) {    
  112.                 index = row * width + col;    
  113.                 ta = (inPixels[index] >> 24) & 0xff;    
  114.                 tr = (inPixels[index] >> 16) & 0xff;    
  115.                 tg = (inPixels[index] >> 8) & 0xff;    
  116.                 tb = inPixels[index] & 0xff;    
  117.                 redSum += tr;    
  118.                 greenSum += tg;    
  119.                 blueSum +=tb;    
  120.             }    
  121.         }  
  122.         int redmeans = (int)(redSum / total);  
  123.         int greenmeans = (int)(greenSum / total);  
  124.         int bluemeans = (int)(blueSum / total);  
  125.         System.out.println(" red average value = " + redmeans);  
  126.         System.out.println(" green average value = " + greenmeans);  
  127.         System.out.println(" blue average value = " + bluemeans);  
  128.         return new Color(redmeans, greenmeans, bluemeans);  
  129.     }  
  130. }  

讨论:

皮肤检测中的后续处理非常重要,可以除去噪声,平滑图像,是皮肤检测的结果

更加的准确,输出的更容易接受。

2018-01-15 18:52:17 u011178262 阅读数 13155

数字图像处理(Digital Image Processing)又称为计算机图像处理,它是指将图像信号转换成数字信号并利用计算机对其进行处理的过程。

图像概述

分类

  • 按图像灰度
    • 灰度图像:一般为256灰度级(8位图)、二值图像
  • 按图像格式
    • 光栅图像:bmp、jpg、png、gif
    • 矢量图像:wmf、svg
  • 按图像维度
  • 全景照片

属性

二维图像

  • 基本单位:像素
  • 分辨率
    • 空间分辨率:单位:PPI(pixels per inch)
    • 灰度级分辨率(色阶)
  • 宽度、高度
  • 幅度信息
    • 灰度
    • 梯度
  • 相位信息

三维图像

  • 基本单位:体素
  • 宽度、高度、深度

像素间关系

  • 邻接性、连通性、区域和边界
  • 距离度量(函数)
    • L1范数:曼哈顿距离、街区距离
    • L2范数:欧式距离(欧几里得距离)
    • L∞范数:切比雪夫距离、棋盘距离

相关

  • 图像与光波波长和振幅的关系
  • 视觉欺骗
  • 人类从外界获取的信息约有百分之七十五来自视觉系统

图像预处理

颜色空间转换

RGB to Gray

RGB三原色合成法

  • 白平衡算法

RGB to HSV

二值化

  • OSTU: 计算一连通区域的阈值,然后对该区域二值化
  • 自适应二值化

图像变换

  • 不考虑插值
    • 平移
    • 翻转/镜像
  • 考虑插值
    • 旋转
    • 缩放(放大:过采样,缩小:欠采样)
    • 错切
  • 傅里叶变换

图像复原和增强

图像平滑(模糊)

突出图像的宽大区域、低频成分、主干部分或抑制图像噪声和干扰高频成分,使图像亮度平缓渐变 ,减小突变梯度。

线性滤波器

基于核矩阵的邻域加权和法计算图像卷积。

  • 低通滤波器
    • 归一化块(均值)滤波器 (Normalized Box Filter)
    • 高斯滤波器 (Gaussian Filter)
非线性滤波器

图像增强(锐化)

增强图像边缘,使图像更加鲜明。

线性滤波器

基于核矩阵的邻域加权和法计算图像卷积。

  • 高通滤波器: 使用微分算法计算图像梯度
    • 计算一阶导数:Sobel(浮雕特效)、Prewitt、Roberts
    • 计算二阶导数:拉普拉斯

图像形态学运算

  • 开运算: 先腐蚀,后膨胀
  • 闭运算: 先膨胀,后腐蚀

图像编码和压缩

预测编码

变换压缩

图像分析

图像特征

  • 统计特征
    • 均值
    • 标准差
    • 方差
  • 结构特征
    • 线
    • 边缘
    • 纹理

图像检测

特征点

  • Harris角点
  • FAST特征(Features from Accelerated Segment Test)
  • SURF特征

边缘

  • 特征:方向、幅度
  • 算子
    • Canny算子:速度快、高低阈值需要输入
    • Sobel算子
    • Prewitt算子
    • Roberts算子

直线/线段

  • 霍夫(Hough)线变换
  • LSD

  • 霍夫(Hough)圆变换

图像分割

基于阈值

基于边缘

基于区域

  • 分水岭分割算法
  • 区域生长法
  • 分裂合并法

基于跟踪

  • 轮廓跟踪法:提取连通区域的轮廓
  • 光栅跟踪法

图像识别和分类

模式识别(Pattern Recognition)

机器学习

人工神经网络

其他图像处理

光学图像处理

基于相位信息的图像处理

相位一致性图像特征检测

应用

肤色检测

  • 连通域在复杂背景肤色检测中的应用
  • Skin Segmentation Using YCbCr and RGB Color Models

人脸检测

OCR

去除阴影

06.OpenCV-图像处理

阅读数 41

FPGA图像处理之路

阅读数 1886

没有更多推荐了,返回首页