js进行数字图像处理:亮度对比度马赛克画笔放大缩小镜像贴纸旋转颜色值显示

Posted 夏日摩卡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js进行数字图像处理:亮度对比度马赛克画笔放大缩小镜像贴纸旋转颜色值显示相关的知识,希望对你有一定的参考价值。

①  亮度调整:进度条拖动实现亮度改变。

②  对比度调整:进度条拖动实现对比度改变。

③  马赛克笔刷:点击图标,在画布上鼠标-点击-拖动实现局部马赛克处理。

④  放大:点击放大图标,实现图片1.2倍放大。可多次点击。

⑤  缩小:点击缩小图标,实现图片0.83倍缩小。可多次点击。

⑥  旋转:点击旋转图标,每次顺时针旋转角度有上方输入框决定。可多次点击。

⑦  垂直镜像:点击图标,实现垂直翻转。

⑧  水平镜像:点击图标,实现水平翻转。

⑨  颜色值显示:点击颜色显示图标,鼠标进入画布移动,可在color块上观测鼠标所在像素的颜色。

叠图:点击贴纸图标,在画布中点击可进行粘贴图样。

 

旋转的插值有点问题,但是同样的算法使用matlab效果很好。

 

采用的程序语言是javascript,图形化界面依靠html、css,依托于html的canvas编写。画布呈现长宽均是实际像素个数。

代码和方法有很多不完美的地方。

注:实现借鉴了很多网上帖

滑动轴

1.  色彩变换原理-亮度调整

1.1算法原理:

    图象亮度是指画面的明亮程度。灰度图像中,灰度值越高则图像越亮。

原像素灰度f(i,j),转换后为g(i,j),g(i,j)=f(i,j)+b,系数影响图像的亮度。随着增加b (b>0)和减小b (b>0),图像整体的灰度值上移或者下移, 也就是图像整体变亮或者变暗。设置b为light,值域为【-255,255】

 

1.2亮度调整

亮度度调整公式如下:

RGB’=RGB+ Light

其中RGB’代表了r,g,b各自重新计算后的值。

 

1.3实施方案

在界面上放置一个滑动轴,范围rgbnum为-50~50,初始值为0。即Light=rgbnum/50*255。除此,叠加对比度调整效果。

拖动条借鉴:https://blog.csdn.net/qq_36818627/article/details/81606778?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

代码如:注:data[i]、data[i+1]、data[i+2]代表RGB。

后续判断对比度是否改变,改变则叠加。这里没有贴代码。

 

 

 

var rgbnum=parseInt(barleft/(scroll.offsetWidth-bar.offsetWidth) * 100-50)
ptxt.innerHTML =  parseInt(rgbnum) + "%";//滚动条获取亮度变化值。
    //data0储存改变亮度对比度之前的图像,防止调节亮度过低或过高只有黑白色了。
    for(var i = 0; i < data.length; i += 4 ) {
        if(parseInt(data0[i]+parseInt(rgbnum)/50*255)>255)
            data[i]=255;
        else if(parseInt(data0[i]+parseInt(rgbnum)/50*255)<0)
            data[i]=0;
        else data[i] = data0[i]+parseInt(rgbnum)/50*255;
        if(parseInt(data0[i+1]+parseInt(rgbnum)/50*255)>255)
            data[i+1]=255;
        else if(parseInt(data0[i+1]+parseInt(rgbnum)/50*255)<0)
            data[i+1]=0;
        else data[i+1] = data0[i+1]+ parseInt(rgbnum)/50*255;
        if(parseInt(data0[i+2]+parseInt(rgbnum)/50*255)>255)
            data[i+2]=255;
        else if(parseInt(data0[i+2]+parseInt(rgbnum)/50*255)<0)
            data[i+2]=0;
        else data[i+2] = data0[i+2]+ parseInt(rgbnum)/50*255;
    }
	

 2色彩变换原理-对比度调整

 

2.1算法原理:

    图像对比度指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,即指一幅图像灰度反差的大小。差异范围越大代表对比越大,差异范围越小代表对比越小。

查阅了图像处理软件Photoshop的对比度调整公式。RGB三个通道分别做相同的调整运算。Contrast是调整参数,取值范围为【-255,255】

 

2.2对比度调整

对比度调整公式如下:

RGB’=RGB+(RGB-Average)*Contrast/255 

其中nRGB’代表了r,g,b各自重新计算后的值。Average是平均亮度,大部分图片是在100~150之间。取127,与实际相近。

所以当Contrast为0时,RGB值不变,表示当前的一个对比度。

为-255时,RGB都为127,亮度都一样,没有差别,呈灰色。

为255时,在Average之上的像素点会变得更亮,反之变得更暗。

 

2.3实施方案

在界面上放置一个滑动轴,范围rgbnum为-50~50,初始值为0。即Contrast/255=rgbnum/50。除此,叠加亮度调整效果。

代码如:注:data[i]、data[i+1]、data[i+2]代表RGB。

 

 

 

var rgbnum=parseInt(barleft0/(scroll0.offsetWidth-bar0.offsetWidth) * 100-50)
    ptxt0.innerHTML =  parseInt(rgbnum) + "%";
    var avg=127;
    //RGB = RGB + (RGB - avg) * Contrast / 255
    for(var i = 0; i < data.length; i += 4 ) {
        if(parseInt(data0[i]+(data0[i]-127)*parseInt(rgbnum)/50)>255)
            data[i]=255;
        else if(parseInt(data0[i]+(data0[i]-127)*parseInt(rgbnum)/50)<0)
            data[i]=0;
        else data[i] = data0[i]+(data0[i+1]-127)*parseInt(rgbnum)/50;
        if(parseInt(data0[i+1]+(data0[i+1]-127)*parseInt(rgbnum)/50)>255)
            data[i+1]=255;
        else if(parseInt(data0[i+1]+(data0[i+1]-127)*parseInt(rgbnum)/50)<0)
            data[i+1]=0;
        else data[i+1] = data0[i+1]+ (data0[i+1]-127)*parseInt(rgbnum)/50;
        if(parseInt(data0[i+2]+(data0[i+2]-127)*parseInt(rgbnum)/50)>255)
            data[i+2]=255;
        else if(parseInt(data0[i+2]+(data0[i+2]-127)*parseInt(rgbnum)/50)<0)
            data[i+2]=0;
        else data[i+2] = data0[i+2]+ (data0[i+2]-127)*parseInt(rgbnum)/50;
    }

 

 3马赛克笔功能

3.1算法原理:

    马赛克像素的rgb=这块马赛克内所有像素rgb的平均值。

 

3.2马赛克笔设置

为了方便查看效果,设定一块马赛克包含(3*2+1)*(3*2+1)=49个像素点。一块马赛克包含的像素点越多,图像模糊化越重。以鼠标点击为中心,一次涂抹马赛克操作包含(3*2)^2个马赛克。

 

3.3实施方案

    处理马赛克画笔的顺序是,鼠标点击(绘制36个马赛克),移动超出一个马赛克1/2长,便会进行下一区域马赛克涂抹。鼠标抬起,绘制完成。

 

 

 方法借鉴: https://www.jianshu.com/p/3d2a8bd83191

4放大

4.1算法原理:

最简单的方式,如果需要将原图像放大为k倍,则将原图像中的每个像素值,填在新图像中对应的k*k大小的子块中。

 

4.2放大算法

设原图像大小为M*N,放大为k1M*k2N,(k1>1,k2>1)。

算法步骤如下:

1)设旧图像是F(i,j), i=1,2,…,M,  j=1,2,…,N.

       新图像是G(i’,j’),  i’=1,2,…,k1M, j’=1,2,…,k2N.

2)G(i’,j’)=F(c1*I’,c2*j’)

       c1=1/k1    c2=1/k2

 

4.3实施方案

    先扩展画布,然后进行等比例填充像素值。

单次放大设置为图像的1.2倍,通过修改代码参数,可修改倍数值,为了界面美观,没有设置可调节倍数。通过点击放大按钮,进行放大图片。

 

 

 

 

for(var i = 0; i < parseInt(oCanvas.width*oCanvas.height); i++) {
            var dx=i%oCanvas.width;
            var dy=(i-dx)/oCanvas.width;
            var mx=parseInt(dx/1.2);
            var my=parseInt(dy/1.2);
            if(parseInt(mx)>parseInt(width))
            {
                mx=width;
            }
            if(parseInt(my)>parseInt(height)){
                my=height;
            }
data[(dy*oCanvas.width+dx)*4+0]=datatemp[(my*width+mx)*4+0];
            data[(dy*oCanvas.width+dx)*4+1]=datatemp[(my*width+mx)*4+1];
            data[(dy*oCanvas.width+dx)*4+2]=datatemp[(my*width+mx)*4+2];
            data[(dy*oCanvas.width+dx)*4+3]=datatemp[(my*width+mx)*4+3];
        }

 

 5.缩小

5.1算法原理:

图像的缩小从物理意义上来说,是将描述图像的每个像素的物理尺寸缩小相应的倍数就可以完成;但如果像素的物理尺寸不允许改变,从数码技术的角度来看,图像的缩小实际上就是通过减少像素个数来实现的。

图像缩小实际上就是对原有的多个数据进行挑选或处理,获得期望 缩小尺寸的数据,并且尽量保持原有的特征不丢失。

最简单的方法就是等间隔地选取数据。

5.2缩小算法

设原图像大小为M*N,缩小为k1M*k2N, (k1<1,k2<1, k1=k2 为按比例缩小, k1!=k2为不按比例缩小)。

算法步骤如下:

1) 设原图为F(i,j), i=1,2,…,M,  j=1,2,…,N.

压缩后图像是G(i’,j’),  i’=1,2,…,k1M,  j’=1,2,…,k2N.

2)G(i’,j’)=F(c1*i’,c2*j’)

其中,c1=1/k1    c2=1/k2

 

5.3实施方案

    先缩小画布,然后进行等间隔取像素值。

单次缩小设置为图像的0.83倍,通过修改代码参数,可修改倍数值,为了界面美观,没有设置可调节倍数。通过点击缩小按钮,进行缩小图片。

 

 

 

 

for(var i = 0; i < parseInt(oCanvas.width*oCanvas.height); i++) {
            var dx=i%oCanvas.width;
            var dy=(i-dx)/oCanvas.width;
            var mx=parseInt(dx*1.2);
            var my=parseInt(dy*1.2);
            if(parseInt(mx)>parseInt(width))
            {
                mx=width;
            }
            if(parseInt(my)>parseInt(height)){
                my=height;
            }
            data[(dy*oCanvas.width+dx)*4+0]=datatemp[(my*width+mx)*4+0];
            data[(dy*oCanvas.width+dx)*4+1]=datatemp[(my*width+mx)*4+1];
            data[(dy*oCanvas.width+dx)*4+2]=datatemp[(my*width+mx)*4+2];
            data[(dy*oCanvas.width+dx)*4+3]=datatemp[(my*width+mx)*4+3];
        }

6.  旋转

6.1旋转原理:

以图像原点逆时针旋转θ角, 设原图像的坐标点为(x0,y0), 则旋转后图像坐标点的计算公式如下:

 

 

 

6.2旋转方案

           图像旋转之前的两个问题:

1)图像旋转计算出的值为小数,而坐标值为正整数。

2)图像旋转计算的结果值所在范围与原来的值所在的范围不同。

因此图像旋转需要做扩大画布,取整处理,平移处理 。

图像旋转之后的两个问题:

1)像素的排列不是完全按照原有的相邻关系。这是因为相邻像素之间只能有8个方向(相邻为45度)

2)会出现许多的空洞点。

因此图像旋转之后需要进行插值处理。

          6.3双线性插值

双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。

红色的数据点与待插值得到的绿色点

假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。

 

 

 

 

首先在 x 方向进行线性插值,得到:

 

然后在 y 方向进行线性插值,得到:

 

 

 

 

这样就得到所要的结果 f(x, y),

 

 

 

如果选择一个坐标系统使得 f 的四个已知点坐标分别为 (0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么插值公式就可以化简为:

f(x,y)=f(0,0)(1-x)(1-y)+f(1,0)x(1-y)+f(0,1)(1-x)y+f(1,1)xy

 

 

 插值空洞太多,效果不好。。。

输入逆时针旋转角度,点击旋转,便可实现旋转功能。
var text=document.getElementById("id_xz0").value;
    console.log(text);
    if(text==NaN||text==undefined ||text==0 ||text==null){
        alert("填入角度");
    }
    var num0=parseInt(text);
    console.log(num0);
    imageData=ctx.getImageData(0,0,oCanvas.width,oCanvas.height);
    data=imageData.data;
    
    var datatemp0=new Array(data.length);
    var datatemp1=new Array(data.length);
    for(var i=0;i<data.length;i++){
        datatemp0[i]=0;
        datatemp1[i]=0;
    }

    var thita=parseFloat(Math.PI*num0/180);
    console.log(oCanvas.width);
    console.log(oCanvas.height);
    for(var i=0;i < parseInt(oCanvas.width*oCanvas.height);i++){
        var dx=i%parseInt(oCanvas.width);
        var dy=(i-dx)/oCanvas.width;
        datatemp0[(dy*oCanvas.width+dx)*4+0]=parseInt(dy+1);
        datatemp0[(dy*oCanvas.width+dx)*4+1]=parseInt(dy+1);
        datatemp0[(dy*oCanvas.width+dx)*4+2]=parseInt(dy+1);
        datatemp0[(dy*oCanvas.width+dx)*4+3]=parseInt(dy+1);

        datatemp1[(dy*oCanvas.width+dx)*4+0]=parseInt(dx+1);
        datatemp1[(dy*oCanvas.width+dx)*4+1]=parseInt(dx+1);
        datatemp1[(dy*oCanvas.width+dx)*4+2]=parseInt(dx+1);
        datatemp1[(dy*oCanvas.width+dx)*4+3]=parseInt(dx+1);
    }
    console.log(datatemp0);
    console.log(datatemp1);

    var datatemp00=new Array(datatemp0.length);
    var datatemp11=new Array(datatemp0.length);
    var max0=0;
    var min0=oCanvas.width+oCanvas.height;
    var max1=0;
    var min1=oCanvas.width+oCanvas.height;
    console.log(Math.cos(thita));
    console.log(Math.sin(thita));
    for(var i=0;i<parseInt(oCanvas.width*oCanvas.height);i++){
        var dx=i%oCanvas.width;
        var dy=(i-dx)/oCanvas.width;
        //逆时针旋转thita度
        datatemp00[(dy*oCanvas.width+dx)*4+0]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+0]*Math.cos(thita)- datatemp1[(dy*oCanvas.width+dx)*4+0]*Math.sin(thita));
        datatemp11[(dy*oCanvas.width+dx)*4+0]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+0]*Math.sin(thita)+ datatemp1[(dy*oCanvas.width+dx)*4+0]*Math.cos(thita));
        
        datatemp00[(dy*oCanvas.width+dx)*4+1]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+1]*Math.cos(thita)- datatemp1[(dy*oCanvas.width+dx)*4+1]*Math.sin(thita));
        datatemp11[(dy*oCanvas.width+dx)*4+1]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+1]*Math.sin(thita)+ datatemp1[(dy*oCanvas.width+dx)*4+1]*Math.cos(thita));
        
        datatemp00[(dy*oCanvas.width+dx)*4+2]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+2]*Math.cos(thita)- datatemp1[(dy*oCanvas.width+dx)*4+2]*Math.sin(thita));
        datatemp11[(dy*oCanvas.width+dx)*4+2]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+2]*Math.sin(thita)+ datatemp1[(dy*oCanvas.width+dx)*4+2]*Math.cos(thita));
        
        datatemp00[(dy*oCanvas.width+dx)*4+3]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+3]*Math.cos(thita)- datatemp1[(dy*oCanvas.width+dx)*4+3]*Math.sin(thita));
        datatemp11[(dy*oCanvas.width+dx)*4+3]= parseInt(datatemp0[(dy*oCanvas.width+dx)*4+3]*Math.sin(thita)+ datatemp1[(dy*oCanvas.width+dx)*4+3]*Math.cos(thita));
        
        if(min0>parseInt(datatemp00[(dy*oCanvas.width+dx)*4+0])){
            min0=datatemp00[(dy*oCanvas.width+dx)*4+0];
        }
        if(min1>parseInt(datatemp11[(dy*oCanvas.width+dx)*4+0])){
            min1=datatemp11[(dy*oCanvas.width+dx)*4+0];
        }
    }

console.log(min0);
console.log(min1);
    for(var j=0;j<datatemp00.length;j++){
        datatemp00[j]=datatemp00[j]+(1-min0);
        datatemp11[j]=datatemp11[j]+(1-min1);
    }
    console.log(datatemp00);
    for(var i=0;i<parseInt(oCanvas.width*oCanvas.height);i++){
        var dx=i%oCanvas.width;
        var dy=(i-dx)/oCanvas.width;
        //逆时针旋转thita度
        if(max0<parseInt(datatemp00[(dy*oCanvas.width+dx)*4+0])){
            max0=datatemp00[(dy*oCanvas.width+dx)*4+0];
        }
        if(max1<parseInt(datatemp11[(dy*oCanvas.width+dx)*4+0])){
            max1=datatemp11[(dy*oCanvas.width+dx)*4+0];
        }
    }
    console.log(max0);
    console.log(max1);
    console.log(datatemp00);
    console.log(datatemp11);
    oCanvas.width=max1;
    oCanvas.height=max0;
    var len=oCanvas.width*oCanvas.height*4;
    var imageDatatemp0=ctx.getImageData(0,0,oCanvas.width,oCanvas.height);
    var data_ =imageDatatemp0.data;
    for(var j=0;j<len;j++){
        data_[j]=0;
    }
    var datalast=data;
    console.log(datalast);

    for(var i=0;i<parseInt(width*height);i++){
        var dx=i%width;
        var dy=(i-dx)/width;
        var mx;
        var my;
        mx=parseInt(datatemp11[(dy*width+dx)*4+0])-1;
        my=parseInt(datatemp00[(dy*width+dx)*4+0])-1;
        data_[(my*oCanvas.width+mx)*4+0]=datalast[(dy*width+dx)*4+0];

        mx=parseInt(datatemp11[(dy*width+dx)*4+1])-1;
        my=parseInt(datatemp00[(dy*width+dx)*4+1])-1;
        data_[(my*oCanvas.width+mx)*4+1]=datalast[(dy*width+dx)*4+1];
        
        mx=parseInt(datatemp11[(dy*width+dx)*4+2])-1;
        my=parseInt(datatemp00[(dy*width+dx)*4+2])-1;
        data_[(my*oCanvas.width+mx)*4+2]=datalast[(dy*width+dx)*4+2];
        
        mx=parseInt(datatemp11[(dy*width+dx)*4+3])-1;
        my=parseInt(datatemp00[(dy*width+dx)*4+3])-1;
        data_[(my*oCanvas.width+mx)*4+3]=datalast[(dy*width+dx)*4+3];
        
    }
    console.log(datalast);
    
    thita=-thita;
    for(var i=0;i<parseInt(oCanvas.width*oCanvas.height);i++){
        var dx=i%oCanvas.width;
        var dy=(i-dx)/oCanvas.width;
        var di=dy+1;
        var dj=dx+1;
        var mx=parseInt(di-(1-min0));
        var my=parseInt(dj-(1-min1));
        var fx=mx*Math.cos(thita)-my*Math.sin(thita);
        var fy=mx*Math.sin(thita)+my*Math.cos(thita);
        var invx=parseInt(mx*Math.cos(thita)-my*Math.sin(thita));//逆时针旋转thita度
        var invy=parseInt(mx*Math.sin(thita)+my*Math.cos(thita));
        var temp;
        if(invx>1 && parseInt(invx)<=height && parseInt(invy)>1 && parseInt(invy)<=width){
            if(data_[(dy*oCanvas.width+dx)*4+3]==0 && data_[(dy*oCanvas.width+dx)*4+2]==0 && data_[(dy*oCanvas.width+dx)*4+1]==0 && data_[(dy*oCanvas.width+dx)*4+0]==0)
            {
                temp = datalast[((invy-2)*height+(invx-2))*4+0]*(invx-fx)*(invy-fy)+datalast[((invy-2)*height+(invx-1))*4+0]*(fx+1-invx)*(invy-fy)+datalast[((invy-1)*height+(invx-2))*4+0]*(fy+1-invy)*(invx-fx)+datalast[((invy-1)*height+(invx-1))*4+0]*(fx+1-invx)*(fy+1-invy);
                data_[(dy*oCanvas.width+dx)*4+0]=parseInt(temp);
             
                temp = datalast[((invy-2)*height+(invx-2))*4+1]*(invx-fx)*(invy-fy)+datalast[((invy-2)*height+(invx-1))*4+1]*(fx+1-invx)*(invy-fy)+datalast[((invy-1)*height+(invx-2))*4+1]*(fy+1-invy)*(invx-fx)+datalast[((invy-1)*height+(invx-1))*4+1]*(fx+1-invx)*(fy+1-invy);
                data_[(dy*oCanvas.width+dx)*4+1]=parseInt(temp);
            
                temp = datalast[((invy-2)*height+(invx-2))*4+2]*(invx-fx)*(invy-fy)+datalast[((invy-2)*height+(invx-1))*4+2]*(fx+1-invx)*(invy-fy)+datalast[((invy-1)*height+(invx-2))*4+2]*(fy+1-invy)*(invx-fx)+datalast[((invy-1)*height+(invx-1))*4+2]*(fx+1-invx)*(fy+1-invy);
                data_[(dy*oCanvas.width+dx)*4+2]=parseInt(temp);
                
                temp = datalast[((invy-2)*height+(invx-2))*4+3]*(invx-fx)*(invy-fy)+datalast[((invy-2)*height+(invx-1))*4+3]*(fx+1-invx)*(invy-fy)+datalast[((invy-1)*height+(invx-2))*4+3]*(fy+1-invy)*(invx-fx)+datalast[((invy-1)*height+(invx-1))*4+3]*(fx+1-invx)*(fy+1-invy);
                data_[(dy*oCanvas.width+dx)*4+3]=parseInt(temp);
            }
        } 
    }

 

 

7.镜像

7.1垂直镜像原理:

       垂直镜像计算公式如下:(图像大小为M*N)

 

 

 

for(var i=0;i<oCanvas.width*oCanvas.height;i++){
        var dx=i%oCanvas.width;
        var dy=(i-dx)/oCanvas.width;
       data[(dy*oCanvas.width+(oCanvas.width-dx-1))*4+0]=datatemp[(dy*oCanvas.width+dx)*4+0];
       data[(dy*oCanvas.width+(oCanvas.width-dx-1))*4+1]=datatemp[(dy*oCanvas.width+dx)*4+1];
       data[(dy*oCanvas.width+(oCanvas.width-dx-1))*4+2]=datatemp[(dy*oCanvas.width+dx)*4+2];
       data[(dy*oCanvas.width+(oCanvas.width-dx-1))*4+3]=datatemp[(dy*oCanvas.width+dx)*4+3];
    }

 

 8水平镜像

水平镜像计算公式如下:(图像大小为M*N)

 

因为表示图像的矩阵坐标不能为负,因此需要在进行镜像计算之后再进行坐标的平移。

                  

 

for(var i=0;i<oCanvas.width*oCanvas.height;i++){
        var dx=i%oCanvas.width;
        var dy=(i-dx)/oCanvas.width;
       data[((oCanvas.height-dy-1)*oCanvas.width+(dx))*4+0]=datatemp[(dy*oCanvas.width+dx)*4+0];
       data[((oCanvas.height-dy-1)*oCanvas.width+(dx))*4+1]=datatemp[(dy*oCanvas.width+dx)*4+1];
       data[((oCanvas.height-dy-1)*oCanvas.width+(dx))*4+2]=datatemp[(dy*oCanvas.width+dx)*4+2];
       data[((oCanvas.height-dy-1)*oCanvas.width+(dx))*4+3]=datatemp[(dy*oCanvas.width+dx)*4+3];
    }

 

 9颜色值显示

原理:鼠标获取鼠标在画布上的位置。通过数据定位获取rgb值显示出来。

 

 截图鼠标截不进去。。。

oCanvas.onmousemove=function(ev){
        var datatemp=imageData0.data;
        var ev=window.event||ev;
        var dx = ev.pageX-oCanvas.offsetLeft;
        var dy = ev.pageY-oCanvas.offsetTop; 
        var pp = parseInt(dy*oCanvas.width+dx); 
        var temp0=parseInt(pp*4);
        var R0 = parseInt(datatemp[temp0+0]);  
        var G0 = parseInt(datatemp[temp0+1]);  
        var B0 = parseInt(datatemp[temp0+2]);
        display.style.background="rgb("+R0+","+G0+","+B0+")";
    }

 

 

10.叠图贴纸

原理:在画布上覆盖原有像素。

点击贴纸按钮,蓝色选中后,便可以直接在画布中任意叠加。
var imgObj=new Image();
    imgObj.crossOrigin="Anonymous";
    imgObj.src="./good.png";
    var img_width = 50;
    var img_height = 50;
    
    oCanvas.onmousedown=function(ev){
        console.log("贴图");
        var ev=window.event||ev;
        var dx = ev.pageX-oCanvas.offsetLeft;
        var dy = ev.pageY-oCanvas.offsetTop;
        ctx.drawImage(imgObj, parseInt(dx-(img_width)/2), parseInt(dy-(img_height)/2),50,50);

 

 

html布局代码:

<html>
<head>
    <title>图像处理大作业</title>

    <link rel="stylesheet" href="./style.css">
</head>

<body>
<div class="background">
    <div class="body-wrapping">  
        <!-- 图片处理前后展示 -->
        <div class="container0">
            <div>
                <p>原图:</p>
                <input type="file" id="input-upload" accept=".jpg,.jpeg,.png,.gif,.svg" placeholder="上传本地图片" />
                <div class="">
                    <img id="input-img" class="">
                </div>
            </div>
        </div>
        <div class="container0">
            <div class="container">
                <p>亮度调节:</p>
                <div class="scroll" id="scroll">
                    <div class="bar" id="bar">
                
                    </div>
                    <div class="mask" id="mask"></div>
                </div>
                <p id="light">0</p>
            </div>
            <div class="container">
                <p>对比度调节:</p>
                <div class="scroll" id="scroll0">
                    <div class="bar" id="bar0">
                
                    </div>
                    <div class="mask" id="mask0"></div>
                </div>
                <p id="compare">0</p>
            </div>
        </div>
        
        <input id="id_xz0" class="text" placeholder="角度°"/>
        
        <div class="icons">
            <li id="msk" onclick="drawmsk(0)"><img src="./msk.png" id="id_msk" class="icon-wrapping"></li>
            <li id="fd" onclick="zoomin(1)"><img src="./fd.png" id="id_fd" class="icon-wrapping"></li>
            <li id="sx" onclick="zoomout(2)"><img src="./sx.png" id="id_sx" class="icon-wrapping"></li>
            <li id="xz" onclick="rotate(3)"><img src="./xz.png" id="id_xz" class="icon-wrapping"></li>
            <li id="jx" onclick="mirror(4)"><img src="./hjx.png" id="id_jx" class="icon-wrapping"></li>
            <li id="hjx" onclick="hmirror(5)"><img src="./jx.png" id="id_hjx" class="icon-wrapping"></li>
        </div>
        <div class="icons">
            <li id="right" onclick="addcanvas0(6)"><img src="./right.png" id="img_right" class="icon-wrapping"></li>
            <li id="wrong" onclick="addcanvas1(7)"><img src="./wrong.png" id="img_wrong" class="icon-wrapping"></li>
            <li id="comeon" onclick="addcanvas2(8)"><img src="./comeon.png" id="img_comeon" class="icon-wrapping"></li>
            <li id="good" onclick="addcanvas3(9)"><img src="./good.png" id="img_good" class="icon-wrapping"></li>
            <li id="displayxy" onclick="addcanvas4(10)"><div class="icon-wrapping icon-text" id="img_displayxy">颜色显示</div></li>
            <li 2新建文档参数

Adobe Illustrator和PS对比两者各都有哪些优势

pc端 前端页面 js灯箱效果能放大缩小吗

图像对比度和亮度

山东大学数字图像处理实验

贪玩巴斯数字图像处理基础课堂笔记——「亮度变换与空间滤波全解——加权平滑滤波器相关&卷积拉普拉斯图像增强变化直方图」 2021-10-1910-1210-25