小程序中如何使用图像处理
2018-09-24 04:06:06 weixin_34220179 阅读数 133

背景

小程序的canvas是微信基于原生组件自行封装的,因此接口跟web的canvas有不少区别,早期更是没有支持像素级的处理能力。
在18年初的小程序基础库1.9.0版本更新中,出现了wx.canvasGetImageData和wx.canvasPutImageData两个重要的API,补全了像素处理能力,因此,小程序在客户端进行图片处理成为了可能。
具体可以参考:
偷偷迭代的重磅功能---小程序的像素处理能力
wx.canvasGetImageData

图片配色分析小程序:小色卡

为了尝试小程序的图像处理能力,我做了个用于图片配色分析的小程序-小色卡。
功能主要是:用户选择一张图片,程序会分析图片的配色,并把配色展示为一张色卡给用户。用户可以保存、编辑、复制自己的色卡。这个功能对初级的UI设计师有一定的帮助(可能吧...)。
源码:github:mini-color-card
体验小程序:
小色卡

原理

小程序实现配色分析主要步骤如下:

  1. 用户选择图片,拿到imgPath后绘制到canvas上。
  2. 通过wx.canvasGetImageData这个接口读取图片数据
  3. 对图片数据进行预处理,剔除alpha比较小并且不是白色的点。(非必要)
  4. 对图片像素数据进行聚类。每个像素的颜色可以作为一个三维向量来看。

基本逻辑如下:

wx.chooseImage({
  count: 1,
  sizeType: ['original', 'compressed'],
  sourceType: ['album', 'camera'],
  success: (res) => {
    wx.getImageInfo({
      src: res.tempFilePaths[0],
      success: (imgInfo) => {
        let {
          width,
          height,
          imgPath
        } = imgInfo;
        let ctx = wx.createCanvasContext(this.canvasID);
        ctx.drawImage(imgPath,0,0,width,height);
        ctx.draw(false,()=>{
          wx.canvasGetImageData({
            canvasId: this.canvasID,
            x: 0,
            y: 0,
            width: width,
            height: height,
            success(res) {
              var pixels = res.data;
              var pixelCount = width*height;
              var pixelArray = [];
              // 对像素数据进行预处理
              for (var i = 0, offset, r, g, b, a; i < pixelCount; i = i + quality) {
                offset = i * 4;
                r = pixels[offset + 0];
                g = pixels[offset + 1];
                b = pixels[offset + 2];
                a = pixels[offset + 3];
                if (a >= 125) {
                  if (!(r > 250 && g > 250 && b > 250)) {
                    pixelArray.push([r, g, b]);
                  }
                }
              }
              var cmap = MMCQ.quantize(pixelArray, colorCount);//聚类,MMCQ是个用于图像分析的库
              var palette = cmap ? cmap.palette() : null;
              console.log('配色为:',palette);
            }
          })
        })
      }
    })
  }
})

小结

一开始我是不想把canvas显示出来的,只想用它获取图像内容,但是实践下来是不可行的。小程序的canvas并不允许离屏渲染,想要用它进行图片处理,就要老老实实用它进行展示。
这里只实践了wx.canvasGetImageData读取数据进行图像分析,不过结合wx.canvasPutImageData,滤镜之类的图像处理应该都是可以做了。小程序的想象空间还是挺大的。

2005-12-12 22:30:00 weixin_33778778 阅读数 85
    功能很简单,主要为了熟悉一下图像处理的基本操作!
    主要功能在一个封装好的类中,功能还写了蛮多的。
    截了几个图,
    源代码 (要的人比较多,所以还是把源代码传了上来)
 

截图1.JPG截图2.JPG截图3.JPG截图4.JPG
2019-03-29 14:53:18 qq_23149979 阅读数 38

小程序介绍:在进行图像处理时,往往需要进行数据输入,输入的数据可能是图片,也可能是视频,本文将从两方面介绍图像读取与显示的内容。
<编辑中,编辑完成将去掉此提示!>

1 读取并显示一张图片

代码如下:

# -*- coding=GBK -*-
import cv2

src = cv2.imread("XXX/XXX.jpg")
cv2.imshow("窗口名称",src) 

cv2.waitKey(0)
cv2.destroyAllWindows()

说明:

  1. -- coding=GBK --
    用于显示中文字符而不至于乱码。
  2. cv2.imread(const String& filename,int flags)
    读取图片文件,需填写准确图片路径。
  3. cv2.imshow(const string& winname, InputArray mat)
    显示图片窗口。
  4. cv2.waitKey(K)
    窗口显示时间,k=0时会一直显示,否则显示k毫秒后关闭窗口。
  5. cv2.destroyAllWindows()
    删除建立的全部窗口,释放资源。

2 视频显示

代码如下:

import cv2

capture = cv2.VideoCapture(0)

while capture.isOpened():
    pressed_key = cv2.waitKey(1)
    _, frame = capture.read()
    frame=cv2.flip(frame,1)
    #实时显示
    cv2.imshow('Original',frame)
    
    cv2.destroyAllWindows()
    capture.release()

3 参考资料

[1]https://blog.csdn.net/u011321546/article/details/79508670

声明

本程序只做学习研究,详情请参考链接内容!
如有疑问,可留言反馈或通过邮件交流(hardenqiu@foxmail.com)

2018-08-22 15:49:09 Replus_ 阅读数 5394

声明:       

       这篇文章的主要目的是通过建立一维傅里叶变换与图像傅里叶变换中相关概念的对应关系来帮助读者理解图像处理中的离散傅里叶变换,因此,理解图像中离散傅里叶变换的前提条件是读者需要了解一维傅里叶变换的基本知识,详情可参考:https://zhuanlan.zhihu.com/p/19763358


基本数学概念的对应关系:

       一维傅里叶变换的作用对象是信号,信号是一维连续的,其数学表现形式如图1所示,该图反应的是随着时间不断推移,信号强度的变换情况,可称为时域:

图1

       而图像处理中的傅里叶变换的作用对象是二维矩阵。二维矩阵的数学表现形式如下图所示,反应了随着位置的不断改变,灰度值大小的变化情况。我们在此将其称为“距离-灰度变化图”:

图2

       从正面看去,由x轴与灰度值轴构成的切面图如图3所示:

图3

       图3与图1的本质是类似的,都是一个自变量一个因变量。因此可以构成对应关系:时间<->距离、信号强度<->灰度值。

傅里叶变换结果的对应关系:

       一维傅里叶变换的原理可以通俗的理解为:将一个复杂无规律的信号拆分成多个简单有规律的子信号来表示(如果对泰勒展开有深刻的理解的话,可以将傅里叶变换理解为将任意一个函数分解为任意个多项式的组合)。如图4所示。

图4

       为了定量表示这个结果,我们用下图进行表达。其中,横轴为频率大小,纵轴为振幅(即信号的最高强度),该图可称为频谱

图5

       通过观察频谱,我们可以发现,频谱中的每个点在时域中都对应一个函数(这个特点很重要,说明了频谱和时域的对应关系是点与线)。

       因此,通过类比,可将图像处理中傅里叶变换理解为:将一个复杂无规律的图像拆分成多个简单有规律的子图像来表示(此处画图太麻烦,请读者自行发挥想象力对图4中的众多子信号,想象成不断起伏的平面)。

       那要如何定量表达众多分解后的子图像呢?

       我们先来看一下图像傅里叶变换后的表现形式,即图像的“频谱”。

       现在,我们就通过类比,来理解这上幅图中的各个方向的自变量到底对应信号频谱中的哪个变量。

       在信号的频谱中,频率的定义为:单位时间内完成周期性变化的次数。而在上文“基本数学概念的对应关系”中,我们已经将时间和距离对应起来了。那么此处只需要将频率定义中的“时间”换成“距离”即可。最终得到用于表达图像傅里叶变换结果的“频谱”中频率的定义:单位距离内完成周期性变化的次数。由于图像中表达距离的单位是像素大小,所以对这个定义进一步可理解为:N个像素内灰度值完成周期性变化的次数。因此我们就成功的将图像“频谱”和信号“频谱”中的自变量联立起来了。在信号频谱中的频率是x(横)轴,而在图像的频谱中频率是(xy轴构成的)平面。距离原点越远,则说明频率越大。因此,窗口边缘处即为高频区域,原点周边即为低频区域。

注意:上文提到了对于信号来说,频谱中的一个点对应子信号时域中的一条线。通过类比,我们可以得出结论:图像频谱中的一个点对应子图像的一整张距离-灰度变化图。(而图像傅里叶变换的数学公式也反应了这个特点)

       同样的,信号频谱中的y轴反应子信号,信号强度的变化范围,而图像频谱中的z轴反应子图像的灰度值的变化范围。频谱窗口中对应的点越亮,则说明该点对应频率的变化范围越大。

总结与举例:

       综上,可对图像频谱进行解读:

       距离原点越远=频率越高=原图中灰度值的变化越频繁。

       灰度值越大=幅值越大=原图中灰度值变化的范围越大。

       因此,低通滤波能保留图像的大致轮廓信息是因为,一张图像所记录到的主要信息(由于受到关照等必然因素的影响)在图像上灰度值的变化是缓慢的,因此主要信息集中在低频区域。而噪音等偶然因素是突然附加到图像上使得灰度值快速变化,而且密密麻麻,这导致N个像元内,灰度值的变化不仅频繁,而且变化的范围还很大。因此,噪音就位于图像频谱的高频区域,表现为高灰度值。

 

 

2009-08-21 06:48:00 ddxkjddx 阅读数 798

图像处理(验证码识别)程序中常用算法:灰度,二值化,去噪(1*1像素或者3*3像素等)欢迎拍砖!

看原始图像:

 

图像灰度化
效果图:


代码:

view plaincopy to clipboardprint?
//灰度  
private void btnGray_Click(object sender, EventArgs e)  
{  
    try 
    {  
        int Height = this.picBase.Image.Height;  
        int Width = this.picBase.Image.Width;  
        Bitmap newbitmap = new Bitmap(Width, Height);  
        Bitmap oldbitmap = (Bitmap)this.picBase.Image;  
        Color pixel;  
        for (int x = 0; x < Width; x++)  
        {  
            for (int y = 0; y < Height; y++)  
            {  
                pixel = oldbitmap.GetPixel(x, y);  
 
                newbitmap.SetPixel(x, y, Gray(pixel));  
            }  
        }  
        this.picBase.Image = newbitmap;  
    }  
    catch (Exception err)  
    {  
        MessageBox.Show("灰度化失败 原因:" + err.Message);  
    }  
}  
 
//灰度化算法  
protected static Color Gray(Color c)  
{  
    int rgb = Convert.ToInt32((double)(((0.3 * c.R) + (0.59 * c.G)) + (0.11 * c.B)));  
    return Color.FromArgb(rgb, rgb, rgb);  

        //灰度
        private void btnGray_Click(object sender, EventArgs e)
        {
            try
            {
                int Height = this.picBase.Image.Height;
                int Width = this.picBase.Image.Width;
                Bitmap newbitmap = new Bitmap(Width, Height);
                Bitmap oldbitmap = (Bitmap)this.picBase.Image;
                Color pixel;
                for (int x = 0; x < Width; x++)
                {
                    for (int y = 0; y < Height; y++)
                    {
                        pixel = oldbitmap.GetPixel(x, y);

                        newbitmap.SetPixel(x, y, Gray(pixel));
                    }
                }
                this.picBase.Image = newbitmap;
            }
            catch (Exception err)
            {
                MessageBox.Show("灰度化失败 原因:" + err.Message);
            }
        }

        //灰度化算法
        protected static Color Gray(Color c)
        {
            int rgb = Convert.ToInt32((double)(((0.3 * c.R) + (0.59 * c.G)) + (0.11 * c.B)));
            return Color.FromArgb(rgb, rgb, rgb);
        }

图像二值化
效果图:


代码:

view plaincopy to clipboardprint?
//二值化  
private void btnDobleValue_Click(object sender, EventArgs e)  
{  
    this.picBase.Image = Binarizate((Bitmap)this.picBase.Image);  
}  
 
public static Bitmap Binarizate(Bitmap map)  
{  
    int tv = ComputeThresholdValue(map);  
    int x = map.Width;  
    int y = map.Height;  
    for (int i = 0; i < x; i++)  
    {  
        for (int j = 0; j < y; j++)  
        {  
            if (map.GetPixel(i, j).R >= tv)  
            {  
                map.SetPixel(i, j, Color.FromArgb(0xff, 0xff, 0xff));  
            }  
            else 
            {  
                map.SetPixel(i, j, Color.FromArgb(0, 0, 0));  
            }  
        }  
    }  
    return map;  

        //二值化
        private void btnDobleValue_Click(object sender, EventArgs e)
        {
            this.picBase.Image = Binarizate((Bitmap)this.picBase.Image);
        }

        public static Bitmap Binarizate(Bitmap map)
        {
            int tv = ComputeThresholdValue(map);
            int x = map.Width;
            int y = map.Height;
            for (int i = 0; i < x; i++)
            {
                for (int j = 0; j < y; j++)
                {
                    if (map.GetPixel(i, j).R >= tv)
                    {
                        map.SetPixel(i, j, Color.FromArgb(0xff, 0xff, 0xff));
                    }
                    else
                    {
                        map.SetPixel(i, j, Color.FromArgb(0, 0, 0));
                    }
                }
            }
            return map;
        }
 
图像去噪(1*1像素)
效果图:

 

<原始>

 

<去噪后>
代码:

view plaincopy to clipboardprint?
private void btnClean11_Click(object sender, EventArgs e)  
        {  
            this.picBase.Image = OperateBitmap.ClearNoise((Bitmap)this.picBase.Image,4);  
        }  
 
        //1*1除噪  
        public static Bitmap ClearNoise(Bitmap bitmap, int MaxNearPoints)  
        {  
            Color piexl;  
            int nearDots = 0;  
            //int XSpan, YSpan, tmpX, tmpY;  
            //逐点判断  
            for (int i = 0; i < bitmap.Width; i++)  
                for (int j = 0; j < bitmap.Height; j++)  
                {  
                    piexl = bitmap.GetPixel(i, j);  
                    if (piexl.R != 255)  
                    {  
                        nearDots = 0;  
                        //判断周围8个点是否全为空  
                        if (i == 0 || i == bitmap.Width - 1 || j == 0 || j == bitmap.Height - 1)  //边框全去掉  
                        {  
                            bitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));  
                        }  
                        else 
                        {  
                            if (bitmap.GetPixel(i - 1, j - 1).R != 255 ) nearDots++;  
                            if (bitmap.GetPixel(i, j - 1).R != 255) nearDots++;  
                            if (bitmap.GetPixel(i + 1, j - 1).R != 255) nearDots++;  
                            if (bitmap.GetPixel(i - 1, j).R != 255) nearDots++;  
                            if (bitmap.GetPixel(i + 1, j).R != 255) nearDots++;  
                            if (bitmap.GetPixel(i - 1, j + 1).R != 255) nearDots++;  
                            if (bitmap.GetPixel(i, j + 1).R != 255) nearDots++;  
                            if (bitmap.GetPixel(i + 1, j + 1).R != 255) nearDots++;  
                            if (nearDots < 4)  
                            bitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));   //去掉单点 && 粗细小3邻边点  
                        }  
 
 
                    }  
                    else  //背景  
                        bitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));  
                }  
            return bitmap;  
        } 
private void btnClean11_Click(object sender, EventArgs e)
        {
            this.picBase.Image = OperateBitmap.ClearNoise((Bitmap)this.picBase.Image,4);
        }

        //1*1除噪
        public static Bitmap ClearNoise(Bitmap bitmap, int MaxNearPoints)
        {
            Color piexl;
            int nearDots = 0;
            //int XSpan, YSpan, tmpX, tmpY;
            //逐点判断
            for (int i = 0; i < bitmap.Width; i++)
                for (int j = 0; j < bitmap.Height; j++)
                {
                    piexl = bitmap.GetPixel(i, j);
                    if (piexl.R != 255)
                    {
                        nearDots = 0;
                        //判断周围8个点是否全为空
                        if (i == 0 || i == bitmap.Width - 1 || j == 0 || j == bitmap.Height - 1)  //边框全去掉
                        {
                            bitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                        }
                        else
                        {
                            if (bitmap.GetPixel(i - 1, j - 1).R != 255 ) nearDots++;
                            if (bitmap.GetPixel(i, j - 1).R != 255) nearDots++;
                            if (bitmap.GetPixel(i + 1, j - 1).R != 255) nearDots++;
                            if (bitmap.GetPixel(i - 1, j).R != 255) nearDots++;
                            if (bitmap.GetPixel(i + 1, j).R != 255) nearDots++;
                            if (bitmap.GetPixel(i - 1, j + 1).R != 255) nearDots++;
                            if (bitmap.GetPixel(i, j + 1).R != 255) nearDots++;
                            if (bitmap.GetPixel(i + 1, j + 1).R != 255) nearDots++;
                            if (nearDots < 4)
                            bitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));   //去掉单点 && 粗细小3邻边点
                        }


                    }
                    else  //背景
                        bitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                }
            return bitmap;
        }
 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gisfarmer/archive/2009/08/12/4438456.aspx

图像处理小词典

阅读数 9

小白做图像处理

阅读数 391

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