EE103(2):图像线性处理

不使用opencv的库函数,完全运用numpy和线性代数知识,我们能在多大程度上处理图像呢

多通道转单通道

  • 可以使用(r,g,b)=(1/3,1/3,1/3)来转换
  • 也可以使用(r,g,b)=(0.299,0.587,0.114)来转换

原图(pixiv id:490219):

在这里插入图片描述

两种转换方式结果对比

在这里插入图片描述

亮度、对比度

y = a x + [ ( 1 − a ) a v g ( x ) + b ] ⋅ 1 y=ax+[(1-a)avg(x)+b]·1 y=ax+[(1a)avg(x)+b]1

  • x为像素矩阵
  • 1为全1矩阵
  • a越大,对比度越高
  • b越大亮度越高

不同的a(0、0.4、0.8、1.2、1.6、2)情况下图像的情况(不同b情况下略):

在这里插入图片描述

变换

  • 水平缩放:对于m*n的原图像,右乘k*m的矩阵A可以水平缩放为k*n的图像。其中,A的纵列代表了缩放过程中对原图像横排每个像素的加权A的横行代表了最终图像横排每个位的生成原图像的纵列代表了最终图像纵列每个位的生成。在缩放过程中,最终图像横排每个位的生成次数应该和原图像不同,并且每次生成时应该对原图像横排不同像素进行加权

    • 临近插值放大一倍的矩阵A: [ 1 1 0 0 . . . 0 0 0 0 1 1 . . . 0 0 0 0 0 0 . . . 0 0 ⋮ 0 0 0 0 . . . 1 1 ] \left[\begin{matrix} 1&1&0&0&...&0&0\\0&0&1&1&...&0&0\\0&0&0&0&...&0&0\\\vdots\\0&0&0&0&...&1&1\end{matrix}\right] 1000100001000100............00010001
    • 线性插值放大一倍的矩阵A: [ 1 0.5 0 0 . . . 0 0 0 0.5 1 0.5 . . . 0 0 0 0 0 0.5 . . . 0 0 ⋮ 0 0 0 0 . . . 0.5 1 ] \left[\begin{matrix} 1&0.5&0&0&...&0&0\\0&0.5&1&0.5&...&0&0\\0&0&0&0.5&...&0&0\\\vdots\\0&0&0&0&...&0.5&1\end{matrix}\right] 10000.50.500010000.50.50............0000.50001
  • 垂直缩放:对于m*n的原图像,左乘n*k的矩阵A可以垂直缩放为m*k的图像。其中,A的横行代表了缩放过程中对原图像纵列每个像素的加权A的纵列代表了最终图像纵列每个位的生成,原图像的横行代表了最终图像横行每个位的生成。在缩放过程中,最终图像纵列每个位的生成次数应该和原图像不同,并且每次生成时应该对原图像纵列不同像素进行加权

    • 临近插值放大一倍的矩阵A: [ 1 0 0 . . . 0 1 0 0 . . . 0 0 1 0 . . . 0 0 1 0 . . . 0 ⋮ 0 0 0 . . . 1 0 0 0 . . . 1 ] \left[\begin{matrix} 1&0&0&...&0\\1&0&0&...&0\\0&1&0&...&0\\0&1&0&...&0\\\vdots\\0&0&0&...&1\\0&0&0&...&1\end{matrix}\right] 110000001100000000..................000011
    • 线性插值放大一倍的矩阵A: [ 1 0 0 . . . 0 0.5 0.5 0 . . . 0 0 1 0 . . . 0 0 0.5 0.5 . . . 0 ⋮ 0 0 0 . . . 0.5 0 0 0 . . . 1 ] \left[\begin{matrix} 1&0&0&...&0\\0.5&0.5&0&...&0\\0&1&0&...&0\\0&0.5&0.5&...&0\\\vdots\\0&0&0&...&0.5\\0&0&0&...&1\end{matrix}\right] 10.5000000.510.5000000.500..................00000.51
  • 旋转、翻转:矩阵旋转与转置

  • 偏移:切片与连接

常用图层混合模式

设像素矩阵 x x x位于像素矩阵 y y y之上且范围比y小,坐标 i , j ∈ x 坐 标 范 围 i,j\in x坐标范围 i,jx

  • 正常: y i j = x i j y_{ij}=x_{ij} yij=xij

  • 变暗系

    • 变暗: y i j = m i n { y i j , x i j } y_{ij}=min\{y_{ij},x_{ij}\} yij=min{yij,xij},分通道比较替换
    • 正片叠底: y i j = y i j ∗ x i j / 255 y_{ij}=y_{ij}*x_{ij}/255 yij=yijxij/255
    • 颜色加深: y i j = ( y i j + x i j − 255 ) ∗ 255 / x i j y_{ij}=(y_{ij}+x_{ij}-255)*255/x_{ij} yij=(yij+xij255)255/xij
    • 线性加深: y i j = y i j + x i j − 255 y_{ij}=y_{ij}+x_{ij}-255 yij=yij+xij255
    • 深色: y i j = m i n { y i j , x i j } y_{ij}=min\{y_{ij},x_{ij}\} yij=min{yij,xij},比较全通道数值

在这里插入图片描述

  • 变亮系

    • 变亮: y i j = m a x { y i j , x i j } y_{ij}=max\{y_{ij},x_{ij}\} yij=max{yij,xij},分通道比较替换
    • 滤色: y i j = 255 − ( 255 − y i j ) ∗ ( 255 − x i j ) / 255 y_{ij}=255-(255-y_{ij})*(255-x_{ij})/255 yij=255(255yij)(255xij)/255
    • 颜色减淡: y i j = y i j + x i j ∗ y i j / ( 255 − y i j ) y_{ij}=y_{ij}+x_{ij}*y_{ij}/(255-y_{ij}) yij=yij+xijyij/(255yij)
    • 线性减淡: y i j = y i j + x i j y_{ij}=y_{ij}+x_{ij} yij=yij+xij
    • 浅色: y i j = m a x { y i j , x i j } y_{ij}=max\{y_{ij},x_{ij}\} yij=max{yij,xij},比较全通道数值

在这里插入图片描述

  • 叠加:根据y的数值来决定使用正片叠底还是滤色,尽量保留y的颜色 { y i j = x i j ∗ y i j / 128 y i j ≤ 128 y i j = 255 − ( 255 − x i j ) ∗ ( 255 − y i j ) / 128 y i j > 128 \begin{cases}y_{ij}=x_{ij}*y_{ij}/128\quad y_{ij}\leq128\\y_{ij}=255-(255-x_{ij})*(255-y_{ij})/128\quad y_{ij}>128\end{cases} {yij=xijyij/128yij128yij=255(255xij)(255yij)/128yij>128

在这里插入图片描述

  • 照射系

    • 柔光:对x数值高的部分保留较好, { y i j = y i j + ( 2 x i j − 255 ) ( y i j − y i j 2 / 255 ) / 255 x i j ≤ 128 y i j = y i j + ( 2 x i j − 255 ) ( y i j / 255 − y i j ) / 255 x i j > 128 \begin{cases}y_{ij}=y_{ij}+(2x_{ij}-255)(y_{ij}-y_{ij}^2/255)/255\quad x_{ij}\leq128\\y_{ij}=y_{ij}+(2x_{ij}-255)(\sqrt{y_{ij}/255}-y_{ij})/255\quad x_{ij}>128\end{cases} {yij=yij+(2xij255)(yijyij2/255)/255xij128yij=yij+(2xij255)(yij/255 yij)/255xij>128
    • 强光:根据x的数值来决定使用正片叠底还是滤色,尽量保留x的颜色 { y i j = x i j ∗ y i j / 128 x i j ≤ 128 y i j = 255 − ( 255 − x i j ) ∗ ( 255 − y i j ) / 128 x i j > 128 \begin{cases}y_{ij}=x_{ij}*y_{ij}/128\quad x_{ij}\leq128\\y_{ij}=255-(255-x_{ij})*(255-y_{ij})/128\quad x_{ij}>128\end{cases} {yij=xijyij/128xij128yij=255(255xij)(255yij)/128xij>128
    • 亮光:尽量保留x的颜色,x亮度高时图像将被降低对比度并且变亮,x亮度低时图像会被提高对比度并且变暗 { y i j = 255 − ( 255 − y i j ) / ( 2 ∗ x i j ) x i j ≤ 128 y i j = y i j / ( 2 ∗ ( 255 − x i j ) ) ∗ 255 x i j > 128 \begin{cases}y_{ij}=255-(255-y_{ij})/(2*x_{ij})\quad x_{ij}\leq128\\y_{ij}=y_{ij}/(2*(255-x_{ij}))*255\quad x_{ij}>128\end{cases} {yij=255(255yij)/(2xij)xij128yij=yij/(2(255xij))255xij>128
    • 线性光:根据x的数值来决定使用线性加深还是线性减淡,尽量保留x的颜色 y i j = 2 ∗ x i j + y i j − 255 y_{ij}=2*x_{ij}+y_{ij}-255 yij=2xij+yij255

在这里插入图片描述

模糊

生成一个 M ∗ N M*N MN的模糊用卷积核x,与原图像y进行卷积运算,即 y i j = ∑ m = 0 M ∑ n = 0 N x m n y i − m , j − n y_{ij}=\displaystyle\sum_{m=0}^{M}\sum_{n=0}^{N}x_{mn}y_{i-m,j-n} yij=m=0Mn=0Nxmnyim,jn

结果的每个ij位置都相当于原图像ij位置左上 M ∗ N M*N MN范围内的像素加权和,因此可以实现模糊

高斯核

生成原理很简单,对于每个位置计算其与右下角横纵距离,代入二维高斯函数即可。sigma越大模糊程度越大

def gaussian(u, v, sigma):
    pi = 3.1416
    intensity = 1 / (2.0 * pi * sigma * sigma) * math.exp(- 1 / 2.0 * ((u ** 2) + (v ** 2)) / (sigma ** 2))
    return intensity

def gaussianKernel(r, sigma):
    kernel = np.zeros([r, r])
    for i in range(r):
        for j in range(r):
            kernel[i, j] = gaussian(r-i,r-j, sigma)
    kernel /= np.sum(np.sum(kernel))
    return kernel

运动模糊核

运动模糊的原理是一个方向上的图像叠加,给出运动模糊的角度和程度,需要生成一个权重和为1的核。对于向右下、左下、右上、左上运动,核分别越靠近左上、右上、左下、右下的权重最大,其中对角线上r个格子中有值

设首项等于公差,解方程 1 = r d + r ( r − 1 ) 2 d 1=rd+\frac{r(r-1)}{2}d 1=rd+2r(r1)d,得 d = 2 r + r 2 d=\frac{2}{r+r^2} d=r+r22

生成核时,从根据不同的弧度情况,从左上、右上、左下、右下分别开始向着弧度对应的方向寻找r个格并在对应点计算等差数列对应项,如果该格已经有值,则在其旁边一格设置项

def mbkernel(agl,r):
    rad=math.radians(agl)
    w=math.ceil(r*np.abs(np.cos(rad)))
    h=math.ceil(r*np.abs(np.sin(rad)))
    if h==0:
        h+=1
    if w==0:
        w+=1
    d=2/(r+r**2)
    kernel=np.zeros((int(h),int(w)))
    for i in range(0,r):
        if np.sin(rad)>=0:
            y=math.floor(h-i*np.sin(rad)-1)
        else:
            y=math.floor(-i*np.sin(rad))
        if np.cos(rad)>=0:
            x=math.floor(i*np.cos(rad))
        else:
            x=math.floor(w+i*np.cos(rad)-1)
        if kernel[y][x]==0:
            kernel[y][x]=(i+1)*d
        else:
            if np.sin(rad)>=0:
                kernel[y+1][x]=(i+1)*d
            else:
                kernel[y-1][x]=(i+1)*d
    return kernel

卷积

opencv提供了卷积函数

dst=cv2.filter2D(src,-1,kernel=k,anchor=(-1,-1))	#anchor默认位于中间,深度为-1默认保持和原图像相同深度
dst=cv2.filter2D(src,-1,kernel=flip(k),anchor=(k.cols-1,k.rows-1))	#真正意义上的卷积,深度为-1默认保持和原图像相同深度

不使用opencv提供的卷积函数,同样可以手写卷积,但运行速度极慢

半径(纵轴)分别为5、15、30下, σ \sigma σ(横轴)分别为10、50、100下高斯模糊的结果

在这里插入图片描述

半径(纵轴)分别为15、50、100下,角度(横轴)分别为 0 o 0^o 0o 4 5 o 45^o 45o 13 5 o 135^o 135o下运动模糊的结果
在这里插入图片描述

差分

水平差分

对于m*n的原图像,右乘m*m的矩阵A可以进行水平差分。其中,A的纵列代表了缩放过程中对原图像横排每个像素的加权A的横行代表了最终图像横排每个位的生成原图像的纵列代表了最终图像纵列每个位的生成。在差分过程中,最终图像横排每个位的生成次数应该和原图像相同,并且每次生成时应该对原图像横排不同像素进行加权(某个像素为1,其下一个像素为-1)

  • 矩阵A: [ 1 0 0 . . . 0 0 − 1 1 0 . . . 0 0 0 − 1 1 . . . 0 0 ⋮ 0 0 0 . . . − 1 1 ] \left[\begin{matrix} 1&0&0&...&0&0\\-1&1&0&...&0&0\\0&-1&1&...&0&0\\\vdots\\0&0&0&...&-1&1\end{matrix}\right] 110001100010............00010001

垂直差分

对于m*n的原图像,左乘n*n的矩阵A可以进行垂直差分。其中,A的横行代表了缩放过程中对原图像纵列每个像素的加权A的纵列代表了最终图像纵列每个位的生成原图像的横行代表了最终图像横行每个位的生成。在缩放过程中,最终图像纵列每个位的生成次数应该和原图像不同,并且每次生成时应该对原图像纵列不同像素进行加权(某个像素为1,其下一个像素为-1)

  • 矩阵A: [ 1 − 1 0 . . . 0 0 1 − 1 . . . 0 0 0 1 . . . 0 ⋮ 0 0 0 . . . − 1 0 0 0 . . . 1 ] \left[\begin{matrix} 1&-1&0&...&0\\0&1&-1&...&0\\0&0&1&...&0\\\vdots\\0&0&0&...&-1\\0&0&0&...&1\end{matrix}\right] 100001100001100...............00011

图像复原

对我们的图像添加10%椒盐噪声

base = cv2.imread("base.jpg",cv2.IMREAD_GRAYSCALE)
noise=np.random.randint(0,100,base.shape)
base=np.where(noise<5,0,base)
base=np.where(noise>=95,255,base)

添加前:

在这里插入图片描述

添加后:

在这里插入图片描述

均值滤波

设半径为r,均值滤波核是一个 r ⋅ r r·r rr,每个位置值为 1 r ⋅ r \frac{1}{r·r} rr1的方阵

kernel=np.zeros((r,r))
kernel+=1/r/r

在这里插入图片描述

分别使用半径为3、5、15的核滤波结果

中值滤波

设半径为r,中值滤波核在图像上滑动,每 r ⋅ r r·r rr个位置统计中值

def med(inputs,R):
    H, W = inputs.shape
    result = np.zeros(inputs.shape)
    H, W = inputs.shape
    for r in range(0, H - R + 1):
        for c in range(0, W - R + 1):
            cur = inputs[r:r + R,c:c + R]
            val = np.median(cur)
            result[r, c] = val
    return result

在这里插入图片描述

分别使用半径为3、5、15的核滤波结果

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值