小程序源码图像处理
2018-09-24 04:06:06 weixin_34220179 阅读数 141

背景

小程序的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
2014-04-28 18:53:05 gateway6143 阅读数 1331

图像反转

 I=imread('nickyboom.jpg');

J=double(I);
J=-J+(256-1);                 %图像反转线性变换
H=uint8(J);
subplot(1,2,1),imshow(I);

subplot(1,2,2),imshow(H);




直方图均衡化

MATLAB 程序实现如下:

I=imread('nickyboom.jpg);

I=rgb2gray(I);

figure;

subplot(2,2,1);

imshow(I);

subplot(2,2,2);

imhist(I);

I1=histeq(I);

figure;

subplot(2,2,1);

imshow(I1);

subplot(2,2,2);

imhist(I1);




均值滤波器

I=imread('nickyboom.jpg');

subplot(231)

imshow(I)

title('原始图像')

I=rgb2gray(I);

I1=imnoise(I,'salt & pepper',0.02);

subplot(232)

imshow(I1)

title(' 添加椒盐噪声的图像')

k1=filter2(fspecial('average',3),I1)/255;          %进行3*3模板平滑滤波

k2=filter2(fspecial('average',5),I1)/255;          %进行5*5模板平滑滤波

k3=filter2(fspecial('average',7),I1)/255;          %进行7*7模板平滑滤波

k4=filter2(fspecial('average',9),I1)/255;          %进行9*9模板平滑滤波

subplot(233),imshow(k1);title('3*3 模板平滑滤波');

subplot(234),imshow(k2);title('5*5 模板平滑滤波');

subplot(235),imshow(k3);title('7*7 模板平滑滤波');

subplot(236),imshow(k4);title('9*9 模板平滑滤波');




中值滤波器

I=imread('nickyboom.jpg');
I=rgb2gray(I);
J=imnoise(I,'salt & pepper',0.02);
subplot(231),imshow(I);title('原图像');
subplot(232),imshow(J);title('添加椒盐噪声图像');
k1=medfilt2(J);            %进行3*3模板中值滤波
k2=medfilt2(J,[5,5]);      %进行5*5模板中值滤波
k3=medfilt2(J,[7,7]);      %进行7*7模板中值滤波
k4=medfilt2(J,[9,9]);      %进行9*9模板中值滤波
subplot(233),imshow(k1);title('3*3模板中值滤波');
subplot(234),imshow(k2);title('5*5模板中值滤波 ');
subplot(235),imshow(k3);title('7*7模 板中值滤波');
subplot(236),imshow(k4);title('9*9 模板中值滤波');




边缘检测

I=imread('nickyboom.jpg');
subplot(2,3,1);
imshow(I);
title('原始图像');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I1=im2bw(I);
subplot(2,3,2);
imshow(I1);
title('二值图像');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I2=edge(I1,'roberts');
subplot(2,3,3);
imshow(I2);
title('roberts算子边缘检测');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I3=edge(I1,'sobel');
subplot(2,3,4);
imshow(I3);
title('sobel算子边缘检测');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系
I4=edge(I1,'Prewitt');
subplot(2,3,5);
imshow(I4);
title('Prewitt算子边缘检测 ');
axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系

I5=edge(I1,'log');

subplot(2,3,6);
imshow(I5);

title('log算子边缘检测');

axis([50,250,50,200]);
grid on;                  %显示网格线
axis on;                  %显示坐标系




自动阈值法:Otsu法

用MATLAB实现Otsu算法:

clc

clear all

I=imread('nickyboom.jpg');

subplot(1,2,1),imshow(I);

title('原始图像')

axis([50,250,50,200]);

grid on;                  %显示网格线

axis on;                  %显示坐标系

level=graythresh(I);     %确定灰度阈值

BW=im2bw(I,level);

subplot(1,2,2),imshow(BW);

title('Otsu 法阈值分割图像')

axis([50,250,50,200]);

grid on;                  %显示网格线

axis on;                  %显示坐标系



膨胀操作

I=imread('nickyboom.jpg');          %载入图像

I1=rgb2gray(I);

subplot(1,2,1);

imshow(I1);

title('灰度图像')     

axis([50,250,50,200]);

grid on;                  %显示网格线

axis on;                  %显示坐标系

se=strel('disk',1);          %生成圆形结构元素

I2=imdilate(I1,se);             %用生成的结构元素对图像进行膨胀

subplot(1,2,2);

imshow(I2);

title(' 膨胀后图像');

axis([50,250,50,200]);

grid on;                  %显示网格线

axis on;                  %显示坐标系



腐蚀操作

MATLAB 实现腐蚀操作

I=imread('xian.bmp');          %载入图像

I1=rgb2gray(I);

subplot(1,2,1);

imshow(I1);

title('灰度图像')     

axis([50,250,50,200]);

grid on;                  %显示网格线

axis on;                  %显示坐标系

se=strel('disk',1);       %生成圆形结构元素

I2=imerode(I1,se);        %用生成的结构元素对图像进行腐蚀

subplot(1,2,2);

imshow(I2);

title('腐蚀后图像');

axis([50,250,50,200]);

grid on;                  %显示网格线

axis on;                  %显示坐标系





2012-11-24 20:39:55 darennet 阅读数 402

#if ! defined (_LOADBMP_H)
#define _LOADBMP_H

#if ! defined (EXTRA_NAME)
#define EXTRA_NAME "~EX."
#endif

#include <afx.h>
#include <iostream.h>
#include <windows.h>
#include <math.h>

#define pi (double)3.14159265359

int nWidth;
int nHeight;
int nLen;
int nByteWidth;
BYTE *lpBackup;
BYTE *lpBitmap;
BYTE *lpBits;
CString FileName;
CString Front;
CString Rear;

/*复数定义*/
typedef struct
{
 double re;
 double im;
}COMPLEX;

/*复数加运算*/
COMPLEX Add(COMPLEX c1, COMPLEX c2)
{
 COMPLEX c;
 c.re=c1.re+c2.re;
 c.im=c1.im+c2.im;
 return c;
}

/*复数减运算*/
COMPLEX Sub(COMPLEX c1, COMPLEX c2)
{
 COMPLEX c;
 c.re=c1.re-c2.re;
 c.im=c1.im-c2.im;
 return c;
}

/*复数乘运算*/
COMPLEX Mul(COMPLEX c1, COMPLEX c2)
{
 COMPLEX c;
 c.re=c1.re*c2.re-c1.im*c2.im;
 c.im=c1.re*c2.im+c2.re*c1.im;
 return c;
}

void GetPoints(BYTE *lpPoints)
{
 int x,y,p;
 for(y=0;y<nHeight;y++)
 {
  for(x=0;x<nWidth;x++)
  {
   p=x*3+y*nByteWidth;
   lpPoints[x+y*nWidth]=(BYTE)(0.299*(float)lpBits[p+2]+0.587*(float)lpBits[p+1]+0.114*(float)lpBits[p]+0.1);
  }
 }
}

void PutPoints(BYTE *lpPoints)
{
 int x,y,p,p1;
 for(y=0;y<nHeight;y++)
 {
  for(x=0;x<nWidth;x++)
  {
   p=x*3+y*nByteWidth;
   p1=x+y*nWidth;
   lpBits[p]=lpPoints[p1];
   lpBits[p+1]=lpPoints[p1];
   lpBits[p+2]=lpPoints[p1];
  }
 }
}

void CuttheName()
{
 int Position;
 Position=FileName.Find('.');
 Front=FileName.Left(Position);
 Rear=FileName.Mid(Position+1);
}

void LoadBitmap()
{
 BITMAPINFOHEADER *pInfo;
 pInfo=(BITMAPINFOHEADER *)(lpBitmap+sizeof(BITMAPFILEHEADER));
 nWidth=pInfo->biWidth;
 nByteWidth=nWidth*3;
 if (nByteWidth%4) nByteWidth+=4-(nByteWidth%4);
 nHeight=pInfo->biHeight;
 if (pInfo->biBitCount!=24)
 {
  if (pInfo->biBitCount!=8)
  {
   cout<<"Invalidation Bitmap";
   delete lpBitmap;
   lpBitmap=0;
   return;
  }
  unsigned int PaletteSize=1<<pInfo->biBitCount;
  if (pInfo->biClrUsed!=0 && pInfo->biClrUsed<PaletteSize) PaletteSize=pInfo->biClrUsed;
  lpBits=lpBitmap+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
  RGBQUAD *pPalette=(RGBQUAD *)lpBits;
  lpBits+=sizeof(RGBQUAD)*PaletteSize;
  nLen=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+nByteWidth*nHeight;
  BYTE *lpTemp=lpBitmap;
  lpBitmap=new BYTE[nLen];
  BITMAPFILEHEADER bmh;
  BITMAPINFOHEADER bmi;
  bmh.bfType='B'+'M'*256;
  bmh.bfSize=nLen;
  bmh.bfReserved1=0;
  bmh.bfReserved2=0;
  bmh.bfOffBits=54;
  bmi.biSize=sizeof(BITMAPINFOHEADER);
  bmi.biWidth=nWidth;
  bmi.biHeight=nHeight;
  bmi.biPlanes=1;
  bmi.biBitCount=24;
  bmi.biCompression=BI_RGB;
  bmi.biSizeImage=0;
  bmi.biXPelsPerMeter=0;
  bmi.biYPelsPerMeter=0;
  bmi.biClrUsed=0;
  bmi.biClrImportant=0;
  int nBWidth=pInfo->biWidth;
  if (nBWidth%4) nBWidth+=4-(nBWidth%4);
  memset(lpBitmap,0,nLen);
  memcpy(lpBitmap,&bmh,sizeof(BITMAPFILEHEADER));
  memcpy(lpBitmap+sizeof(BITMAPFILEHEADER),&bmi,sizeof(BITMAPINFOHEADER));
  BYTE *lpBits2=lpBitmap+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
  int x,y,p1,p2,Palette;
  for(y=0;y<nHeight;y++)
  {
   for(x=0;x<nWidth;x++)
   {
    p1=y*nBWidth+x;
    p2=y*nByteWidth+x*3;
    if (lpBits[p1]<PaletteSize) Palette=lpBits[p1];
    else Palette=0;
    lpBits2[p2]=pPalette[Palette].rgbBlue;
    lpBits2[p2+1]=pPalette[Palette].rgbGreen;
    lpBits2[p2+2]=pPalette[Palette].rgbRed;
   }
  }
  delete lpTemp;
 }
 lpBits=lpBitmap+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
 if (lpBackup) delete lpBackup;
 lpBackup=new BYTE[nLen];
 memcpy(lpBackup,lpBitmap,nLen);
}

void OpenFile() 
{
 CFile File=0;
 if (!File.Open(FileName,CFile::modeRead)) return;
 CuttheName();
 if (lpBitmap) delete lpBitmap;
 nLen=File.GetLength();
 lpBitmap=new BYTE[nLen];
 File.Read(lpBitmap,nLen);
 LoadBitmap(); 
}

void SaveAs()
{
 CFile file;
 if (lpBitmap==0) return;
 if (!file.Open(Front+EXTRA_NAME+Rear,CFile::modeWrite|CFile::modeCreate))
 {
  cout<<"ERROR~~\n";
  return;
 }
 int nLen=nByteWidth*nHeight;
 BYTE *pMem=new BYTE[nLen+sizeof(BITMAPINFOHEADER)];
 BITMAPINFOHEADER *bmi=(BITMAPINFOHEADER *)pMem;
 bmi->biSize=sizeof(BITMAPINFOHEADER);
 bmi->biWidth=nWidth;
 bmi->biHeight=nHeight;
 bmi->biPlanes=1;
 bmi->biBitCount=24;
 bmi->biCompression=BI_RGB;
 bmi->biSizeImage=0;
 bmi->biXPelsPerMeter=0;
 bmi->biYPelsPerMeter=0;
 bmi->biClrUsed=0;
 bmi->biClrImportant=0;
 BITMAPFILEHEADER bmh;
 bmh.bfType='B'+'M'*256;
 bmh.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+nLen;
 bmh.bfReserved1=0;
 bmh.bfReserved2=0;
 bmh.bfOffBits=54;
 memcpy(pMem+sizeof(BITMAPINFOHEADER),lpBits,nLen);
 file.Write(&bmh,sizeof(BITMAPFILEHEADER));
 file.Write(pMem,nLen+sizeof(BITMAPINFOHEADER));
 file.Close();
}

#endif

2012-10-26 09:38:58 ninver2007 阅读数 687

#if ! defined (_LOADBMP_H)
#define _LOADBMP_H

#if ! defined (EXTRA_NAME)
#define EXTRA_NAME "~EX."
#endif

#include <afx.h>
#include <iostream.h>
#include <windows.h>
#include <math.h>

#define pi (double)3.14159265359

int nWidth;
int nHeight;
int nLen;
int nByteWidth;
BYTE *lpBackup;
BYTE *lpBitmap;
BYTE *lpBits;
CString FileName;
CString Front;
CString Rear;

/*复数定义*/
typedef struct
{
 double re;
 double im;
}COMPLEX;

/*复数加运算*/
COMPLEX Add(COMPLEX c1, COMPLEX c2)
{
 COMPLEX c;
 c.re=c1.re+c2.re;
 c.im=c1.im+c2.im;
 return c;
}

/*复数减运算*/
COMPLEX Sub(COMPLEX c1, COMPLEX c2)
{
 COMPLEX c;
 c.re=c1.re-c2.re;
 c.im=c1.im-c2.im;
 return c;
}

/*复数乘运算*/
COMPLEX Mul(COMPLEX c1, COMPLEX c2)
{
 COMPLEX c;
 c.re=c1.re*c2.re-c1.im*c2.im;
 c.im=c1.re*c2.im+c2.re*c1.im;
 return c;
}

void GetPoints(BYTE *lpPoints)
{
 int x,y,p;
 for(y=0;y<nHeight;y++)
 {
  for(x=0;x<nWidth;x++)
  {
   p=x*3+y*nByteWidth;
   lpPoints[x+y*nWidth]=(BYTE)(0.299*(float)lpBits[p+2]+0.587*(float)lpBits[p+1]+0.114*(float)lpBits[p]+0.1);
  }
 }
}

void PutPoints(BYTE *lpPoints)
{
 int x,y,p,p1;
 for(y=0;y<nHeight;y++)
 {
  for(x=0;x<nWidth;x++)
  {
   p=x*3+y*nByteWidth;
   p1=x+y*nWidth;
   lpBits[p]=lpPoints[p1];
   lpBits[p+1]=lpPoints[p1];
   lpBits[p+2]=lpPoints[p1];
  }
 }
}

void CuttheName()
{
 int Position;
 Position=FileName.Find('.');
 Front=FileName.Left(Position);
 Rear=FileName.Mid(Position+1);
}

void LoadBitmap()
{
 BITMAPINFOHEADER *pInfo;
 pInfo=(BITMAPINFOHEADER *)(lpBitmap+sizeof(BITMAPFILEHEADER));
 nWidth=pInfo->biWidth;
 nByteWidth=nWidth*3;
 if (nByteWidth%4) nByteWidth+=4-(nByteWidth%4);
 nHeight=pInfo->biHeight;
 if (pInfo->biBitCount!=24)
 {
  if (pInfo->biBitCount!=8)
  {
   cout<<"Invalidation Bitmap";
   delete lpBitmap;
   lpBitmap=0;
   return;
  }
  unsigned int PaletteSize=1<<pInfo->biBitCount;
  if (pInfo->biClrUsed!=0 && pInfo->biClrUsed<PaletteSize) PaletteSize=pInfo->biClrUsed;
  lpBits=lpBitmap+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
  RGBQUAD *pPalette=(RGBQUAD *)lpBits;
  lpBits+=sizeof(RGBQUAD)*PaletteSize;
  nLen=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+nByteWidth*nHeight;
  BYTE *lpTemp=lpBitmap;
  lpBitmap=new BYTE[nLen];
  BITMAPFILEHEADER bmh;
  BITMAPINFOHEADER bmi;
  bmh.bfType='B'+'M'*256;
  bmh.bfSize=nLen;
  bmh.bfReserved1=0;
  bmh.bfReserved2=0;
  bmh.bfOffBits=54;
  bmi.biSize=sizeof(BITMAPINFOHEADER);
  bmi.biWidth=nWidth;
  bmi.biHeight=nHeight;
  bmi.biPlanes=1;
  bmi.biBitCount=24;
  bmi.biCompression=BI_RGB;
  bmi.biSizeImage=0;
  bmi.biXPelsPerMeter=0;
  bmi.biYPelsPerMeter=0;
  bmi.biClrUsed=0;
  bmi.biClrImportant=0;
  int nBWidth=pInfo->biWidth;
  if (nBWidth%4) nBWidth+=4-(nBWidth%4);
  memset(lpBitmap,0,nLen);
  memcpy(lpBitmap,&bmh,sizeof(BITMAPFILEHEADER));
  memcpy(lpBitmap+sizeof(BITMAPFILEHEADER),&bmi,sizeof(BITMAPINFOHEADER));
  BYTE *lpBits2=lpBitmap+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
  int x,y,p1,p2,Palette;
  for(y=0;y<nHeight;y++)
  {
   for(x=0;x<nWidth;x++)
   {
    p1=y*nBWidth+x;
    p2=y*nByteWidth+x*3;
    if (lpBits[p1]<PaletteSize) Palette=lpBits[p1];
    else Palette=0;
    lpBits2[p2]=pPalette[Palette].rgbBlue;
    lpBits2[p2+1]=pPalette[Palette].rgbGreen;
    lpBits2[p2+2]=pPalette[Palette].rgbRed;
   }
  }
  delete lpTemp;
 }
 lpBits=lpBitmap+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
 if (lpBackup) delete lpBackup;
 lpBackup=new BYTE[nLen];
 memcpy(lpBackup,lpBitmap,nLen);
}

void OpenFile()
{
 CFile File=0;
 if (!File.Open(FileName,CFile::modeRead)) return;
 CuttheName();
 if (lpBitmap) delete lpBitmap;
 nLen=File.GetLength();
 lpBitmap=new BYTE[nLen];
 File.Read(lpBitmap,nLen);
 LoadBitmap();
}

void SaveAs()
{
 CFile file;
 if (lpBitmap==0) return;
 if (!file.Open(Front+EXTRA_NAME+Rear,CFile::modeWrite|CFile::modeCreate))
 {
  cout<<"ERROR~~\n";
  return;
 }
 int nLen=nByteWidth*nHeight;
 BYTE *pMem=new BYTE[nLen+sizeof(BITMAPINFOHEADER)];
 BITMAPINFOHEADER *bmi=(BITMAPINFOHEADER *)pMem;
 bmi->biSize=sizeof(BITMAPINFOHEADER);
 bmi->biWidth=nWidth;
 bmi->biHeight=nHeight;
 bmi->biPlanes=1;
 bmi->biBitCount=24;
 bmi->biCompression=BI_RGB;
 bmi->biSizeImage=0;
 bmi->biXPelsPerMeter=0;
 bmi->biYPelsPerMeter=0;
 bmi->biClrUsed=0;
 bmi->biClrImportant=0;
 BITMAPFILEHEADER bmh;
 bmh.bfType='B'+'M'*256;
 bmh.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+nLen;
 bmh.bfReserved1=0;
 bmh.bfReserved2=0;
 bmh.bfOffBits=54;
 memcpy(pMem+sizeof(BITMAPINFOHEADER),lpBits,nLen);
 file.Write(&bmh,sizeof(BITMAPFILEHEADER));
 file.Write(pMem,nLen+sizeof(BITMAPINFOHEADER));
 file.Close();
}

#endif

图像处理小词典

阅读数 9

小白做图像处理

阅读数 391

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