R语言可以做哪些有趣的事情

2019-11-20 03:52:24

用R语言P图了解一下?其实,Photoshop本质是一种数学软件,它把图片作为一个矩阵来处理,只不过隐藏了内部的数学原理。所以PS能做的,R语言在一定程度上也可以做。首先介绍一个最为简单的软件包,名字叫做“jpeg”,里面仅包含两个函数:一个是读取jpg,一个是写入jpg,而使用方法更是简单无比。我们以Windows7自带的图片“沙漠”为例:orgpic=readJPEG("Desert.jpg")原图如下:敲一下dim(orgpic),你会发现结果是:76810243,也就是说,这是一个array,代表了1024*768的一幅图片,每个像素点都由一个三维向量(R,G,B)来描述。我们可以这样访问一个像素点:orgpic[300,400,]结果并不是一般人在PS类软件常见的0到255之间的整数,而是0到1之间的浮点数,例如:(0.8352941,0.7254902,0.6431373);其实这并不是一个真正的连续性变量。你可以试一下unique(c(orgpic))实际上只有256个不同的值。换句话说,这个函数只是把离散的数据转化成貌似连续的数据而已。我们在PS软件里常看见R,G,B三个通道的直方图。在这里可以很轻松的做到。命令就是:hist(orgpic[,,1])#Rhist(orgpic[,,2])#Ghist(orgpic[,,3])#B除了直方图,我们也可以轻松使用均值,中位数,方差等各式各样的常见统计学功能。反正在这里,图像只是一堆数据而已。下面来做一个负片效果:neg_pic=1-orgpic如上,将每一个像素的RGB均变为用1减去原数值,这正是负片的特点。我们还需要把图片写入文件来实际观察。可以使用writeJPEG函数,其中quality参数控制写入jpg文件的品质:writeJPEG(neg_pic,target="neg_Desert.jpg",quality=0.95)效果如下图:是不是略酷?虽然没有什么实际的用途……接下来可以做出很多类似操作。比如,原图像的平方是什么?writeJPEG(orgpic^2,target="square_Desert.jpg",quality=0.95)看起来似乎比原来的图像更深沉了。如果是相反的操作,取平方根呢?writeJPEG(sqrt(orgpic),target="sqrt_Desert.jpg",quality=0.95)你猜对了,图片会更加明亮清淡一些。难道这就是所谓日系小清新的奥秘?事实上,常见的PS操作,本质都是一些数学运算。比如调整曲线就是建立一个映射,最简单的降噪方法就是加权平均。调整对比,亮度,饱和等等这些原理也都不复杂。下面我们可以自己定义一个分段二次函数:seg_curve<-function(orgpic,low,high){high=min(high,2)low=min(low,2)high=max(high,-2)low=max(low,-2)trans<-function(x){(x<0.5)*(low*x^2+(1-0.5*low)*x)+(x>=0.5)*(-high*x^2+(1+1.5*high)*x-0.5*high)}newpic=trans(orgpic)return(newpic)}这个分段二次函数,以0.5为中心点。当x<0.5时,函数定义为low*x^2+(1-0.5*low)*x;当x>=0.5时,函数定义为-high*x^2+(1+1.5*high)*x-0.5*high,这里low与high都是我们需要指定的参数。这个函数有如下性质:f(0)=0,f(0.5)=0.5,f(1)=1;在[0,1]区间内单调增,是连续可导函数。这里我们可以看到,其实这个分段二次函数就是一种“曲线”。单调增的性质表明,如果原来这个像素点是R>G>B,加工后还是,不会改变图像原有的基本观感。而两个端点的限制则主要是为了保证取值在我们允许的范围内。f(0.5)=0.5这个限制比较特殊,它的意思就是说,尽可能的不大幅改变中间调附近的颜色。这跟前面的平方函数就不同。平方函数直接就把0.5变成0.25了,图像整体会变暗,要是更高次方,可能就接近于0,黑乎乎一片了。而此处的限制,基本上保证图像在“能看”的范围内。其中的两个参数,low和high分别控制高光与阴影,取值范围都在[-2,2]内,即使你指定了范围之外的值也会自动恢复到边界。当这两个数值设置的比较大时,亮部会更亮,暗部会更暗,直观看就是对比度增强。反之,如果取得是负数,图片会变得比较“苍白”。如果是0的话,那么就退化为恒等的一次函数。我们来看看例子:writeJPEG(seg_curve(orgpic,2,2),target="seg2.jpg",quality=0.95)下图看起来似乎是蓝天更鲜艳了,也许是对比/饱和度加强?下面来做另一个例子,反转负冲。这里需要分别控制R,G,B三个通道。下面这个函数的基本原理就是,对G,B通道,反相(例如1-orgpic[,,3])后正片叠底(temp[,,3]*temp[,,3])再与原片混合(b*temp[,,3]+(1-b)*orgpic[,,3]);对于R通道,不反相而直接颜色加深(2-1/temp[,,1])。注:不难证明,2-1/temp[,,1]<=temp[,,1],利用的是均值不等式。changehue<-function(orgpic,r,g,b){newpic=orgpictemp=orgpictemp[,,3]=b*(1-orgpic[,,3])+(1-b)*orgpic[,,3]temp[,,3]=temp[,,3]*temp[,,3]newpic[,,3]=b*temp[,,3]+(1-b)*orgpic[,,3]temp[,,2]=g*(1-orgpic[,,2])+(1-g)*orgpic[,,2]temp[,,2]=temp[,,2]*temp[,,2]newpic[,,2]=g*temp[,,2]+(1-g)*orgpic[,,2]temp[,,1]=2-1/temp[,,1]temp[,,1][temp[,,1]<0]=0newpic[,,1]=r*temp[,,1]+(1-r)*newpic[,,1]return(newpic)}writeJPEG(changehue(orgpic,0.7,0.2,0.5),target="changehue.jpg",quality=0.95)效果是不是很神奇?下面我再提供四个转换用函数,就是RGB色彩模式与HSL,HSV色彩模式之间互相转换的关系。RGB当然大家都知道。但是,我们一般谈论颜色,很少会说“某某分量占多少”,更多的时候我们的表达方式可能是:比较深,比较浅,等等。那么这就与HSL或HSV色彩模式相关。这里H是Hue,色相。S是Saturation,饱和度。L是明度,V是色调。基础知识可以参考网络资源。我这里程序写的效率很低,还有很多可改进的空间。首先就是RGB转HSL。rgbtohsl<-function(original){dx=dim(original)[1]dy=dim(original)[2]dz=dim(original)[3]if(is.na(dz))return(original)temp=array(dim=c(dx,dy,3))maxmatrix=pmax(original[,,1],original[,,2],original[,,3])minmatrix=pmin(original[,,1],original[,,2],original[,,3])if(all.equal(maxmatrix,minmatrix)==TRUE){temp[,,1]=0temp[,,2]=0temp[,,3]=original[,,1]return(temp)}difmatrix=maxmatrix-minmatrixtemph=temp[,,1]temph=(maxmatrix==original[,,1]&original[,,2]>original[,,3])*(60*(original[,,2]-original[,,3])/difmatrix)temph=temph+(maxmatrix==original[,,1]&original[,,2]<original[,,3])*(60*(original[,,2]-original[,,3])/difmatrix+360)temph=temph+((original[,,2]>=original[,,3])&(original[,,2]>original[,,1]))*(60*(original[,,3]-original[,,1])/difmatrix+120)temph=temph+((original[,,3]>original[,,1])&(original[,,3]>original[,,2]))*(60*(original[,,1]-original[,,2])/difmatrix+240)temph[difmatrix==0]=0temp[,,1]=temphtemp[,,3]=0.5*(maxmatrix+minmatrix)temps=temp[,,2]temps=(temp[,,3]>0&temp[,,3]<=0.5)*(difmatrix/temp[,,3]/2)temps=temps+(temp[,,3]>0.5)*(difmatrix/(2-2*temp[,,3]))temps[difmatrix==0]=0temp[,,2]=tempsreturn(temp)}然后HSL转RGB。hsltorgb<-function(hslm){dx=dim(hslm)[1]dy=dim(hslm)[2]dz=dim(hslm)[3]if(is.na(dz))return(hslm)temp=array(dim=c(dx,dy,3))if(sum(hslm[,,2])==0){temp[,,1]=hslm[,,3]temp[,,2]=hslm[,,3]temp[,,3]=hslm[,,3]return(temp)}h=hslm[,,1]s=hslm[,,2]l=hslm[,,3]q=(l<0.5)*(l*(1+s))+(l>=0.5)*(l+s-l*s)p=2*l-qhk=h/360trgb=array(dim=c(dx,dy,3))trgb[,,1]=hk+1/3trgb[,,2]=hktrgb[,,3]=hk-1/3trgb=trgb+1*(trgb<0)-1*(trgb>1)for(iin1:3){temp[,,i]=(trgb[,,i]<1/6)*(p+(q-p)*6*trgb[,,i])temp[,,i]=temp[,,i]+(trgb[,,i]<1/2&trgb[,,i]>=1/6)*qtemp[,,i]=temp[,,i]+(trgb[,,i]<2/3&trgb[,,i]>=1/2)*(p+(q-p)*6*(2/3-trgb[,,i]))temp[,,i]=temp[,,i]+(trgb[,,i]>=2/3)*p}return(temp)}接下来是RGB转HSV。rgbtohsv<-function(original){dx=dim(original)[1]dy=dim(original)[2]dz=dim(original)[3]if(is.na(dz))return(original)temp=array(dim=c(dx,dy,3))maxmatrix=pmax(original[,,1],original[,,2],original[,,3])minmatrix=pmin(original[,,1],original[,,2],original[,,3])if(all.equal(maxmatrix,minmatrix)==TRUE){temp[,,1]=0temp[,,2]=0temp[,,3]=original[,,1]return(temp)}difmatrix=maxmatrix-minmatrixtemph=temp[,,1]temph=(maxmatrix==original[,,1]&original[,,2]>original[,,3])*(60*(original[,,2]-original[,,3])/difmatrix)temph=temph+(maxmatrix==original[,,1]&original[,,2]<original[,,3])*(60*(original[,,2]-original[,,3])/difmatrix+360)temph=temph+((original[,,2]>=original[,,3])&(original[,,2]>original[,,1]))*(60*(original[,,3]-original[,,1])/difmatrix+120)temph=temph+((original[,,3]>original[,,1])&(original[,,3]>original[,,2]))*(60*(original[,,1]-original[,,2])/difmatrix+240)temph[difmatrix==0]=0temp[,,1]=temphtemp[,,3]=maxmatrixtempv=temp[,,2]tempv=difmatrix/maxmatrixtempv[maxmatrix==0]=0temp[,,2]=tempvreturn(temp)}最后是HSV转RGB。hsvtorgb<-function(hsvm){dx=dim(hsvm)[1]dy=dim(hsvm)[2]dz=dim(hsvm)[3]if(is.na(dz))return(hsvm)temp=array(dim=c(dx,dy,3))if(sum(hsvm[,,2])==0){temp[,,1]=hsvm[,,3]temp[,,2]=hsvm[,,3]temp[,,3]=hsvm[,,3]return(temp)}h=hsvm[,,1]s=hsvm[,,2]v=hsvm[,,3]hi=floor(h/60)%%6f=h/60-hip=v*(1-s)q=v*(1-f*s)t=v*(1-(1-f)*s)temp[hi==0]=array(c(v,t,p),dim=c(dx,dy,3))[hi==0]temp[hi==1]=array(c(q,v,p),dim=c(dx,dy,3))[hi==1]temp[hi==2]=array(c(p,v,t),dim=c(dx,dy,3))[hi==2]temp[hi==3]=array(c(p,q,v),dim=c(dx,dy,3))[hi==3]temp[hi==4]=array(c(t,p,v),dim=c(dx,dy,3))[hi==4]temp[hi==5]=array(c(v,p,q),dim=c(dx,dy,3))[hi==5]return(temp)}线性渐变滤镜,通常用来压暗天空。我们这里的基本思路是:先把RGB转为HSL,利用L通道来进行处理。在每一行,线性的减少一些亮度,到最顶上,亮度减为原来的80%。dx=dim(orgpic)[1]dy=dim(orgpic)[2]temp=rgbtohsl(orgpic)nlayer=0.2/dxfor(iin0:(dx-1)){temp[dx-i,,3]=temp[dx-i,,3]-nlayer*i}newpic=hsltorgb(temp)writeJPEG(newpic,target="linear.jpg",quality=0.95)不难看出,效果确实是天空变的更蓝了。我再来一个关于“暗角”的小函数。原理很简单,计算每个像素点与画面中心的距离,如果大于一定的距离,则亮度减低。减低的速度是指数级别的,可以通过参数灵活的控制这个速度。vignetting<-function(orgpic,intensity){dx=dim(orgpic)[1]dy=dim(orgpic)[2]centerx=dx/2centery=dy/2D=max(c(dx,dy))D2=D^2/4for(iin1:dx){for(jin1:dy){d=(i-centerx)^2+(j-centery)^2if(d>D2)newpic[i,j,]=newpic[i,j,]*exp(-(d-D2)/D2*intensity)}}return(newpic)}writeJPEG(vignetting(orgpic,0.5),target="vig.jpg",quality=0.95)效果如下,这是明显的圆圈暗角。下面再来一个很灵活的转换为黑白的函数:RGBBW<-function(orgpic,r,g,b){newpic=orgpicnewmatrix=(r*orgpic[,,1]+g*orgpic[,,2]+b*orgpic[,,3])/(r+g+b)newpic[,,1]=newmatrixnewpic[,,2]=newmatrixnewpic[,,3]=newmatrixreturn(newpic)}这个函数最终返回一个加权平均值,权重可以自定。比如RGBBW(orgpic,1,0,0)就相当于给照片加了个红色滤镜。我们来随便做个例子:writeJPEG(RGBBW(orgpic,2,1,2),target="bw.jpg",quality=0.95)效果如下:在人像照片处理中,假设人物穿的是蓝色的衣服,那么,如果直接加红色滤镜,衣服就会看起来像是黑的。能否让人脸的红色表现得更白,同时衣服也不要太黑呢?用这个就可以:RGBBW(orgpic,2,1,2),这样的话绿色通道会得到抑制,而红色与蓝色都会变强,相当于一个近似的绿色截止滤镜,可以看到草地就变黑了。下面来写一个非常简单的降噪过程,用的都是现有的软件包fields:library(fields)zr<-orgpic[,,1]zg<-orgpic[,,2]zb<-orgpic[,,3]smoothr=image.smooth(zr,theta=0.8)smoothg=image.smooth(zg,theta=0.8)smoothb=image.smooth(zb,theta=0.8)newpic[,,1]=smoothr$znewpic[,,2]=smoothg$znewpic[,,3]=smoothb$zwriteJPEG(newpic,target="antinoise.jpg",quality=0.95)问题在于,原图其实并没有很多噪点,所以加了去燥过程后,实际效果是更加模糊了。最后谈两个相关问题。众所周知,宾得相机的色彩风格很有特点。虽然我们没有办法知道很细节的东西,不过,我们可以做一个简单粗暴的假设:宾得机身直出jpg不同风格的算法只是对RGB三个通道做分别的计算,那么实际是很容易做逆向工程的。比如说,首先用自然模式拍一张照片,然后利用宾得的机身处理功能,分别生成鲜明,人像,风景,风雅,明亮等风格的照片。接下来,我们把这几张图片读入R当中,以自然模式的数据作为x,以其他风格的数据作为y,做一个模型拟合。因为操作步骤较多,因此这里不再赘述。个人测试的结果看,还是颇有些神似的。关于RAW图像的问题,我个人以为重新写一个解码器是不现实的,不过,我确实发现了一个变通的办法。dcraw是一款开源的RAW解码包软件,支持很多新的相机,dcraw可以在这里下载:http://www.cybercom.net/~dcoffin/dcraw/本文作者:京东金融-消费者金融部-决策科学部-张登峰Ph.D

上一篇:360云盘资源如何搜索
下一篇:白日梦想家这部电影值得看吗
设为首页 | 保存到桌面 | 网站地图 | 用户帮助 | 用户注册 | 在线投稿 | 广告投放 | 留言反馈
Copyright © 2005-2012 ™ 165163.com.All Rights Reserved. 东阳在线版权所有
地址:浙江省东阳市画水镇华阳 电话:0579-86220017 013509201192 QQ:393614973 互联网ICP备案编号:浙ICP备10046462号
温馨提示:东阳在线所有帖子仅且代表作者本人意见,均不代表本站立场;如转载请注明出东阳在线(www.165163.com),商业用途请联系本站。

东阳E网 金华公安网监
s