2019-06-09 20:55:09 weixin_41049188 阅读数 659

一,什么是Sobel算子

  • Sobel算子是像素图像边缘检测中最重要的算子之一
  • Sobel算子是一个离散微分算子。(discrete differentiation operator)用来计算图像灰度的近似值
  • Sobel算子功能集合了高斯平滑和微分求导
  • 又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方向和Y方向的梯度图像。

官方图例:

在这里插入图片描述
在图片中 红圈处,是头发和脸交汇处(边缘),是不同的颜色,他们之间的像素差别最大。是像素值发生跃迁的地方,变化曲线可以用f(t)f(t)表示,f(t)f(t)函数图中红圈表示变化最大的点,而对f(t)f(t) 求导 得到 f(t)f`(t)。差值变化曲线,像一个钟摆行。最高处代表边缘点(差值最大处)。
如果f(t)f(t) 看作函数的话,f(t)f`(t)就是他的导函数,我们通过前一个像素和当前像素的差值,边缘处得到最大体现,而非边缘处的差值很小或几乎是0,得到最小体现,然后整个图像进行积分求导,提取最大体现的边缘。

卷积应用-- 边缘提取:

  1. 边缘是什么,是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取,对象检测,模式识别等方面都有很重要的作用。
  2. 如何获取边缘 ,对图像求他的一阶导数。
    delta=f(x)f(x1) delta=f(x) - f(x -1)
    deltadelta 越大,说明像素在 X 的方向变换越大,边缘信号越强。

二,Sobel算子:

Sobel算子是基于权重比,来扩大像素之间的差异,从而更好的寻找边缘。下面两个矩阵都是对称的。

水平梯度:
Gx=[10+120+210+1]I G_x=\left[ \begin{matrix} -1 & 0 & +1 \\ -2& 0 & +2 \\ -1 & 0 & +1 \end{matrix} \right] *I

垂直梯度:
Gy=[121000+1+2+1]I G_y=\left[ \begin{matrix} -1 & -2 & -1 \\ 0& 0 & 0 \\ +1 & +2 & +1 \end{matrix} \right] *I

最终图像梯度:

  1. G=Gx2+Gy2 G= \sqrt{G_x^2+G_y^2}
  2. 默认的计算方式: G=Gx+Gy G= |G_x|+|G_y|

OpenCv中边缘加强算子 (Cv2.Scharr函数):
在求取导数的近似值,kernel=3kernel=3 时不是很准确,OpenCv 使用了改进版本 Cv2.Scharr函数,其算子如下:
Gx=[30+3100+1030+3]I G_x=\left[ \begin{matrix} -3 & 0 & +3 \\ -10& 0 & +10\\ -3 & 0 & +3 \end{matrix} \right] *I
Gy=[3103000+3+10+3]I G_y=\left[ \begin{matrix} -3 & -10 & -3 \\ 0& 0 & 0 \\ +3 & +10 & +3 \end{matrix} \right] *I

三,API

Cv2.Sobel():使用扩展的Sobel算子计算第一、第二、第三或混合图像导数

参数 说明
InputArray src 源图像
OutputArray dst 输出图像
MatType ddepth 输出图像的深度
int xorder X方向 ,几阶导数
int yorder Y方向 ,几阶导数
int ksize = 3 Sobel算子 kernel大小,必须是奇数,1,3,5,7,… …
double scale = 1 计算的导数值的可选缩放因子(默认情况下,不应用缩放),就是放大或缩小计算结果
double delta = 0 可选的增量值,在将结果存储到dst之前添加到结果中,相当于一个增益值
BorderTypes borderType = BorderTypes.Reflect101 边缘处理类型,默认即可

MatType ddepth参数值:计算后的值可能大于 255 所以要选择对应的数据类型,否则计算的结果可能有错误。

Input depth(src.depth()) Output depth (ddepth)
CV_8U -1/CV_16S/CV_32F/CV_64F
CV_16U/CV_16S -1/CV_32F/CV_64F
CV_32F -1/CV_32F/CV_64F
CV_64F -1/CV_64F

改进版 Cv2.Scharr() 参数与上面一样。

边缘提取步骤:

  1. 高斯平滑滤波,Sobel算子对噪声比较敏感,为了不影响计算结果,要进行降噪处理。
  2. 转为灰度色彩空间
  3. 求X方向和Y 方向的梯度图像
  4. 根据公式得到最终图像(振幅图像,X梯度+Y梯度)

四,代码:

	    /// <summary>
        /// Sobel算子图像边缘处理
        /// </summary>
        private static void Sobel(string path)
        {
            using (Mat src = new Mat(path, ImreadModes.AnyColor | ImreadModes.AnyDepth))
            {
                //1:高斯模糊平滑
                Mat dst = new Mat();
                Cv2.GaussianBlur(src, dst, new Size(3, 3), 0, 0, BorderTypes.Default);
                //转为灰度
                Mat gray = new Mat();
                Cv2.CvtColor(dst, gray, ColorConversionCodes.BGR2GRAY);

                MatType m = src.Type();

                //求 X 和 Y 方向的梯度  Sobel  and scharr
                Mat xgrad = new Mat();
                Mat ygrad = new Mat();
                Cv2.Sobel(gray, xgrad, MatType.CV_16S, 1, 0, 3);
                Cv2.Sobel(gray, ygrad, MatType.CV_16S, 0, 1, 3);

                Cv2.ConvertScaleAbs(xgrad, xgrad);//缩放、计算绝对值并将结果转换为8位。不做转换的化显示不了,显示图相只能是8U类型 
                Cv2.ConvertScaleAbs(ygrad, ygrad);

                //加强边缘检测
                //Cv2.Scharr(gray, xgrad, -1, 1, 0, 3);
                //Cv2.Scharr(gray, ygrad, -1, 0, 1, 3);

                Mat output = new Mat(xgrad.Size(), xgrad.Type());
                //图像混合相加(基于权重 0.5)不精确
                //Cv2.AddWeighted(xgrad, 0.5, ygrad, 0.5, 0, output);

                //基于 算法 G=|Gx|+|Gy|    
                int width = xgrad.Cols;
                int hight = xgrad.Rows;
                //for (int x = 0; x <hight ; x++)
                //{
                //    for (int y = 0; y < width; y++)
                //    {
                //        int xg = xgrad.At<byte>(x, y);
                //        int yg = ygrad.At<byte>(x, y);
                //        //byte xy =(byte) (xg + yg);
                //        int v = xg + yg;
                //        if(v>255)
                //        {
                //            v = 255;
                //        }
                //        if(v<0)
                //        {
                //            v = 0;
                //        }
                //        byte xy = (byte)v;
                //        output.Set<byte>(x, y, xy);
                //    }
                //}

                //基于 G= (Gx*Gx +Gy*Gy)的开方根
                for (int x = 0; x < hight; x++)
                {
                    for (int y = 0; y < width; y++)
                    {
                        int xg = xgrad.At<byte>(x, y);
                        int yg = ygrad.At<byte>(x, y);
                        //byte xy =(byte) (xg + yg);
                        double v1 = Math.Pow(xg, 2);
                        double v2 = Math.Pow(yg, 2);
                        int val = (int)Math.Sqrt(v1 + v2);
                        if (val > 255) //确保像素值在 0 -- 255 之间
                        {
                            val = 255;
                        }
                        if (val < 0)
                        {
                            val = 0;
                        }
                        byte xy = (byte)val;
                        output.Set<byte>(x, y, xy);
                    }
                }
                using (new Window("X Image", WindowMode.Normal, xgrad))
                using (new Window("Y Image", WindowMode.Normal, ygrad))
                using (new Window("OUTPUT Image", WindowMode.Normal, output))
                using (new Window("SRC", WindowMode.Normal, src))
                {
                    Cv2.WaitKey(0);
                }
            }
        }

X 向量 和 Y向量
在这里插入图片描述
源图与最终合成输出图像,边缘非常清晰。
在这里插入图片描述

2019-02-20 13:56:59 qq_37954086 阅读数 174

阅读本文大约需要 2 分钟

在这里插入图片描述

1、remove.bg

看名字也能猜出来网站的功能,网站利用图像识别技术,检测人像区域,去除图片背景,实现自动快速抠图。搞过 PS 的人都知道,抠图比较难的应该就是人像图片了,尤其是头发部分。这里传了一张人像图片,可以看出效果还是提不错的。另外,网站也提供第三方的接口,可以在自己的代码中使用。

在这里插入图片描述

网站链接:https://www.remove.bg/

2、photomosh

《银翼杀手》、《攻壳机动队》等科幻电影构建了一个风格独特的赛博朋克(Cyberpunk)世界,也催生了一种名为故障艺术(Glitch Art)的设计风格,近年越来越受到设计师的追捧。PhotoMosh 工具中就提供了这种故障特效,能够方便快捷的生成很多故障特效图片。

在这里插入图片描述

首先根据提示选择一张本地图片,网页右侧会生成相应的特效选项。常用的有像素模糊、RGB 偏移、波纹、摇晃等等基本特效,还有其他一些非常酷炫的特效可供选择,所有的特效可以叠加使用。下面图片是生成效果,感觉还不错,可以导出为图片、GIF以及视频格式。

在这里插入图片描述

网站链接:https://photomosh.com/

3、Algorithmia

网页可以自己上传图片或者输入图片 URL,经过分析后,生成上色的图片。例如这里使用的一张图片,可以看到网页能够辨别出图片中的物体,并加上相应的颜色。例如天空则填充蓝色,山脉则填充黄白色,植被填充相应的绿色,还有对阴影处理得非常到位。

在这里插入图片描述

图片上色只是是这个网站的一个小功能,其他相关功能有例如:图片标签、图片物体识别等等,并且网站提供第三方接口,可以在自己的代码或者应用中接入。

网站链接:https://demos.algorithmia.com/colorize-photos/


文章首发于公众号「嗜码」,欢迎关注

欢迎加我微信,一起交流,互相学习,共同进步!

在这里插入图片描述
关注公众号『嗜码』。回复关键字「前端」、「Python」、「Java」、「Android」、「小程序」、「Vue」等获取免费精品学习资料。
在这里插入图片描述

2015-07-19 15:12:39 jxt1234and2010 阅读数 4023

肤色检测

在人像美化中,肤色检测有助于防止磨掉头发、胡子等需要保持细节的部分,也可以使美白算法仅作用于皮肤,不对人像周边环境产生影响。
网上找了一下肤色检测模型,效果都太差,换了一种思维,找个训练集,自己做一个。
训练结果,正确率大概85%,运行起来,确实还是比网上找的公式好,勉强可用了。

模型

算法最终反映为 opengl 的一个片断着色器,直接看shader代码吧。

varying vec2 textureCoordinate;

uniform sampler2D inputImageTexture;
const vec3 CbC = vec3(0.5,-0.4187,-0.0813);
const vec3 CrC = vec3(-0.1687,-0.3313,0.5);

void main()
{
    vec3 color = texture2D(inputImageTexture, textureCoordinate).rgb;
    float x0 = color.r;
    float x1 = color.g;
    float x2 = color.b;
    float x3 = dot(CbC, color);
    float x4 = dot(CrC, color);
    float pos = 0.0;
    pos = float(x4 <=-0.0615369 ? (x3 <=0.0678488 ? (x3 <=0.0352417 ? 0 : (x2 <=0.686631 ? 0 : 1)) : (x3 <=0.185183 ? 1 : 0)) : (x4 <=-0.029597 ? (x3 <=0.0434402 ? 0 : (x1 <=0.168271 ? 0 : 1)) : 0));
    gl_FragColor = vec4(pos);
}

肤色检测结果

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

训练方法

准备数据集

找到这个网站:
http://blog.csdn.net/wangkr111/article/details/44514097
下载了一组肤色检测的数据,用python脚本将其转换为机器学习所需的矩阵数据。提取 r、g、b、y、cb、cr分量值。

训练

机器学习库

机器学习算法库是自己造的轮子,使用C++开发,特别重视Cache命中率,部分地方引入OpenCL加速,性能可以说是一流的。
使用的代码如下:

#include "learn/ALLearnFactory.h"
#include "core/ALExpanderFactory.h"
#include "core/ALILabeldMethod.h"
#include "core/ALLabeldMethodFactory.h"
#include "learn/ALDecisionTree.h"
#include "loader/ALStandardLoader.h"
#include "learn/ALLogicalRegress.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <math.h>
#include "learn/ALRegressor.h"
using namespace std;
int main()
{
    ALSp<ALFloatDataChain> c = ALStandardLoader::load("../../Data/Face_Dataset/train.data");
    ALSp<ALFloatMatrix> X;
    ALSp<ALFloatMatrix> Y;
    ALStandardLoader::divide(c.get(), X, Y, 0);
    //ALSp<ALISuperviseLearner> learner = new ALLogicalRegress(10000, 1.0);
    ALSp<ALISuperviseLearner> learner = new ALDecisionTree(10, 0.01, 3);//决策树深限制为3
    //ALSp<ALISuperviseLearner> learner = new ALRegressor;
    ALSp<ALIMatrixPredictor> detected = learner->vLearn(X.get(),Y.get());
    ALSp<ALFloatMatrix> YP = ALFloatMatrix::create(Y->width(), Y->height());
    detected->vPredict(X.get(), YP.get());
    size_t po = 0;
    size_t pp = 0;
    size_t fo = 0;
    size_t fp = 0;
    /*验证正确率*/
    for (size_t i=0; i<YP->height(); ++i)
    {
        auto y = *(Y->vGetAddr(0, i));
        auto yp = *(YP->vGetAddr(0, i));
        if (yp > 0.5 && y > 0.5)
        {
            pp++;
        }
        if (yp <=0.5 && y <=0.5)
        {
            fp++;
        }
        if (y > 0.5)
        {
            po++;
        }
        else
        {
            fo++;
        }
    }
    printf("PP/PO: %ld/%ld, %f, FP/FO: %ld/%ld, %f\n", pp, po, (double)pp/(double)po, fp, fo, (double)fp/(double)fo);
    ofstream of("model_logical");
    /*打印模型*/
    detected->vPrint(of);

    return 0;
}

模型选择

一开始本来用的是逻辑回归,因为这个出来的预测公式很简单,shader上运行速度快,但它的效果实在不行。后面改用了决策树,限制树深,以免模型太大。
至于为什么不用SVM:SVM出来的模型在shader上根本没法运行啊。。。

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