Python 数据类型对运算的影响

虽然Python是弱类型编程语言,但是不同的数据类型对计算结果有很大的影响。这点和Matlab不同。
下面以numpy.gradient()函数对一幅图像做梯度运算来说明。这里写图片描述

python源码如下,是Feature extraction & image processing for computer vision (3rd edition) 中 code 4.17 的实现:

import cv2
import numpy as np
import matplotlib.pyplot as plt
def GradCorner(img,op='tan'):
    # img = np.mat(img,dtype=np.float32)

    row,col = img.shape
    img_out = np.zeros((row,col))

    Mx, My= np.gradient(img,edge_order=2)
    # Mx = cv2.Sobel(img,cv2.CV_32FC1,1,0)
    # My = cv2.Sobel(img,cv2.CV_32FC1,0,1)

    EdgeX = cv2.Sobel(img,cv2.CV_32FC1,1,0)
    EdgeY = cv2.Sobel(img,cv2.CV_32FC1,0,1)
    Mag = np.sqrt(EdgeX**2+EdgeY**2)
    # plt.subplot(144);plt.imshow(Mag);plt.title('Edge');plt.show()
    A = np.arctan2(-Mx,My)
    # max supression ,to be impleted...
    Mxx,Mxy = np.gradient(Mx,1)
    Myx,Myy = np.gradient(My,1)

    # comput curvature
    for x in np.arange(col):
        for y in np.arange(row):
            if Mag[y,x]!=0:
                My2=My[y,x]**2;Mx2=Mx[y,x]**2;MxMy=Mx[y,x]*My[y,x]
                if Mx2+My2!=0:
                    if op=='Ti':
                        img_out[y,x]=(1/(Mx2+My2)**1.5)*(My2*Mxx[y,x]-MxMy*Myx[y,x]
                                                         -Mx2*Myy[y,x]+MxMy*Mxy[y,x])
                    elif op=='N':
                        img_out[y, x] = (1 / (Mx2 + My2) ** 1.5) * (Mx2 * Myx[y, x]-MxMy * Mxx[y, x]
                                                                     - MxMy * Myy[y, x] + My2 * Mxy[y, x])
                    elif op=='NI':
                        img_out[y, x] = (1 / (Mx2 + My2) ** 1.5) *(-Mx2 * Myx[y, x]+MxMy * Mxx[y, x]
                                                                   - MxMy * Myy[y, x] + My2 * Mxy[y, x])
                    else :
                        img_out[y, x] = (1 / (Mx2 + My2) ** 1.5) * (-My2 * Mxx[y, x] - MxMy * Myx[y, x]
                                                                    + Mx2 * Myy[y, x] - MxMy * Mxy[y, x])

    plt.subplot(221);plt.imshow(img);plt.title('origin')
    plt.subplot(222);plt.imshow(Mx);plt.title('grad X')
    plt.subplot(223);plt.imshow(My);plt.title('grad Y')
    plt.subplot(224);plt.imshow(img_out);plt.title('Corner');plt.show()
    # plt.tight_layout()
    return img_out

if __name__ == '__main__':
    image = cv2.imread('u.tif',flags=0)
    image = cv2.resize(image,(100,100))
    corimg = GradCorner(image,op='TI')
    # cv2.imshow('orign',image)
    # cv2.imshow('gradcorner',corimg)
    # cv2.waitKey()
    plt.imshow(corimg)
    plt.show()

如果第10行是采用numpy 的gradient函数:

Mx, My= np.gradient(img,edge_order=2)

那么求梯度的结果是:
这里写图片描述

显然求出的梯度和最终的角点都不正确:不论是X方向还是Y方向,从255(红)变0(蓝)的梯度都没有计算出来。查找gradient实现的源码,有这样一段代码(function_base.py, 1077-1084行):

# Use second order differences where possible
out = np.empty_like(y, dtype=otype)

slice1[axis] = slice(1, -1)
slice2[axis] = slice(2, None)
slice3[axis] = slice(None, -2)
# 1D equivalent -- out[1:-1] = (y[2:] - y[:-2])/2.0
out[slice1] = (y[slice2] - y[slice3])/2.0

其实,out的计算就是将原来的输入矩阵y 在某一个维度偏移了两个位置,求其差,作为梯度。这一步后,out的计算就不正确了。Debug时发现out是uint8类型,差值中的负值-255会被算为1。查看out的元素,也印证了这一想法。如果把最后一句改为:

out[slice1] = (y[slice3] - y[slice2])/2.0

那么没有出现的梯度就出现了,而原来出现的又没有了。
所以在自己的代码中加了:

img = np.mat(img,dtype=np.float32)

将uint8类型强制转换为float32,最终的结果就正确了:
这里写图片描述

在图像处理中,cv2.imread的返回结果大多是unsigned类型,虽然在python代码中没有直接指出,但是在运算的时候,python还是严格遵循了不同类型运算的法则。
Python是弱类型,但不是没有数据类型。
这一点需要引起大家的注意。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值