function f(img,s) {
let h = img.length;
let w = img[0].length;
let dh = h * s;
let dw = w * s;
let dis = [];
for(let r=0;r<dh;r++){
let row = [];
for(let c=0;c<dw;c++){
let u = c/dw;
let v = r/dh;
let u1 = u * w;
let v1 = v * h;
let u2 = parseInt(u1);
let v2 = parseInt(v1);
let node = img[v2][u2];
row.push(node)
}
dis.push(row);
}
console.log(dis)
}
f([[0,50],
[150,200]],2)
function f(img,s) {
let h = img.length;
let w = img[0].length;
let dh = h * s;
let dw = w * s;
let dis = [];
for(let r=0;r<dh;r++){
let row = [];
for(let c=0;c<dw;c++){
let u = c/dw;
let v = r/dh;
let u1 = u * w;
let v1 = v * h;
let u2 = parseInt(u1);
let v2 = parseInt(v1);
v1 = v1 - v2;
u1 = u1 - u2;
let bottom = u2+1 < h ? u2+1 : u2;
let right = v2+1 < w ? v2+1 : v2;
let leftTop = img[v2][u2];
let leftBottom = img[v2][bottom];
let rightTop = img[right][u2];
let rightBottom = img[right][bottom];
let val = leftTop* (1-v1) * (1-u1) + leftBottom * u1 * (1-v1) + rightTop * v1 * (1-u1) + rightBottom * v1 * u1;
row.push(val)
}
dis.push(row);
}
console.log(dis)
}
f([[0,50],
[150,200]],2)
0
50
150
200
放大两倍
0
25
50
50
75
100
125
125
150
175
200
200
150
175
200
200
双三次内插法
原理同双线性内插是一样的,只不过它包括了16个最近邻点,计算量增加,效果强于双线性内插。
平移/旋转
平移
预设偏移量 D ( D是一个矩阵,例如[10,15],就是向下移动10,向右移动15)
output[X,Y] = Input[X,Y] + D
旋转
预设旋转角度 R,再预设两个矩阵,调整原点矩阵O和旋转矩阵R、还原原点矩阵D
output[X,Y] = Input[X,Y] * O * R * D
function rotate90(imgVer) {
let dist = [];
let angle = 90;
let ih = imgVer.length;
let iw = imgVer[0].length;
let ow = ih;
let oh = iw;
let rad = angle * Math.PI/180;
let rotateVer = [
Math.cos(rad),-Math.sin(rad),0,
Math.sin(rad),Math.cos(rad),0,
0,0,1
];
let ori = [
1,0,0,
0,-1,0,
-0.5*(iw-1),0.5*(ih-1),1
];
let dec = [
1,0,0,
0,-1,0,
0.5*(iw-1),0.5*(ih-1),1
];
for(let r=0;r<oh;r++){
dist.push([]);
}
for(let r=0;r<ih;r++){
for(let c=0;c<iw;c++){
let result = verMul([r,c,1],ori);
result = verMul(result,rotateVer);
result = verMul(result,dec);
let x = Math.round(result[0]);
let y = Math.round(result[1]);
dist[x][y] = imgVer[r][c]
}
}
return dist;
}
function verMul(a,b){
let r1= a[0]*b[0] + a[1]*b[3] + a[2]*b[6];
let r2= a[0]*b[1] + a[1]*b[4] + a[2]*b[7];
let r3= a[0]*b[2] + a[1]*b[5] + a[2]*b[8];
return [(r1),(r2),(r3)];
}
console.log(rotate90([
[1,2,3],
[4,5,6],
[7,8,9],
],90))
1
2
3
4
5
6
7
8
9
旋转90度之后
3
6
9
2
5
8
1
4
7
两张图片如何叠加?
假设宽高一致的情况
不透明度图片叠加
targetImg = overlayImg
透明图片叠加
预设透明度T(介于0~1),
targetImg = originImg * (1-T) + T * overlayImg
如果宽高位置不一致,需先计算宽高和叠加位置
如何提高/降低亮度?
预设亮度值V(通常介于-150~150)
targetImg = originImg + V
对比度是怎么实现的?
当我们在说增强对比度的时候,本质上就是让亮的更亮,暗的更暗,降低对比度则相反。
自动化对比度实现
先采样图像内的最高像素值Max和最低像素值Min(通常是取前5%最高/最低像素值的平均数,防止结果与预期产生偏差)
预设对比系数K, k = 255/(Max-Min)
targetImg = k(inputImg-Min)
function gaussian(img){
let ver = [
-1,-1,-1,0,-1,1,
0,-1,0,0,0,1,
1,-1,1,0,1,1
];
let ver2 = [
0.094,0.118,0.094,
0.118,0.148,0.118,
0.094,0.118,0.094,
];
let out = img.copy();
let rows = img.rows;
let cols = img.cols;
for(let r=0;r<rows;r++){
for(let c=0;c<cols;c++){
let r1,g,b;
r1 = g = b = 0;
let num = 0;
for(let i=0;i<ver.length;i+=2){
let x = r+ver[i];
let y = c+ver[i+1];
if(x < 0){
x = 0
}else if(x >= rows){
x = rows - 1;
}
if(y<0){
y = 0;
}else if(y >= cols){
y = cols-1;
}
let rgb = img.at(x,y);
r1 += rgb.x * ver2[num];
g += rgb.y * ver2[num];
b += rgb.z * ver2[num];
num++;
}
out.set(r,c,[r1,g,b])
}
}
return out;
}
关于图像处理
前文,前几个月接触了不少图像处理的内容,也做了一些相关东西,最近复习了一下图像处理的一些基础知识,做一些记录并分享。如有错误,望指出。
什么是图像?
从计算机的角度看,使用二进制流所表示离散值的集合
在编程语言内的展示形式:base64,binary stream,uint8array,matrix...
关于像素
主流使用的是0~255,即一字节(8比特),双字节在高质量图像保存也经常被使用,一个经典的图片压缩策略便是将双字节图像压缩成单字节,绝大部分显示设备的颜色范围都不会超出单字节所能表示的精度。
关于灰度
再讲灰度
我们目前看到的大部分图像,都是基于三通道(rgb)或四通道(rgba),即彩色图像。
我们把单通道(只有rgb中的一种)(从黑到白的单色)图像称之灰度图,
二值化
设定一个临界值,大于这个值设为最大值,小于这个值(255),设为最小值(0)
放大/缩小/旋转
将放大/缩小的坐标,换算到百分比,映射到原始坐标上,完成插值(这种方法最简单,但是效果极差,不推荐使用)
放大两倍
使用4个最近邻点进行求值拟合
f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
放大两倍
原理同双线性内插是一样的,只不过它包括了16个最近邻点,计算量增加,效果强于双线性内插。
平移/旋转
两张图片如何叠加?
不透明度图片叠加
透明图片叠加
如何提高/降低亮度?
对比度是怎么实现的?
当我们在说增强对比度的时候,本质上就是让亮的更亮,暗的更暗,降低对比度则相反。
滤波(均值/中值/锐化/高斯/双边/...)
绝大部分滤波都是基于滤波器模版(卷积核),这个模版一般是基于3x3 或 5x5 或 7x7... (必须是奇数)
均值/中值滤波
锐化滤波
高斯滤波
双边滤波
前面介绍的两种滤波在平滑图像的过程中也带来了一个问题,图像平滑的同时,图像边缘也被平滑了;
双边滤波即可平滑图像,也可保留边缘,在像素波动不大的地方进行滤波的时候,效果跟高斯滤波效果是一样的,而到了像素波动起伏大的时候,才是它真正起作用的地方。
像素权重:
像素值越接近,权重越高;颜色差距越大,权重越低,低到忽略不计,
我们求 XY=[1,1]位置的输出值,根据高斯模糊计算(只计算空间距离权重
加上一个像素距离权重之后就变成
边缘检测
先进行图像缩放,高斯滤波降噪,图像二值化,然后进行BFC或DFC(广度搜索或深度搜索的图搜索)
图像匹配/分类/识别/重建
目前这类工作基本上已经完全被机器学习所占领了,越来越多的图像处理工作迁移到了机器学习上,想接触图像处理的话,这方面是必然会遇到的。
关于机器学习原理和机制我也不是太懂,但是目前市面上存在着非常多的开源轮子,理论上是可以开箱即用,所以不懂原理并不影响我们去使用深度学习框架训练我们自己的模型。
在可以简单谈谈我所理解的,如何基本去使用这些框架轮子:
绝大部分机器学习都是基于监督式学习,除了监督式学习还有半监督式,无监督学习。
所谓监督式学习即我们需要先标注好数据;
半监督即只给部分数据打标注;
无监督即只输入数据并进行标注,无监督学习一般适用于GAN(生成式对抗网络);
一般上手步骤:
例如做一个目标检测模型:
PS:以上仅限于使用,只是作为业余爱好者的尝试,无法让你真正的懂得或理解机器学习,也不能让你有能力去修改调优框架能力。
如果真的是感兴趣,应该去接触一些真正的机器学习课程和书籍,跟着课程书籍上面的学习步骤进行。