编程规范

循环用的临时变量

  • 避免用ij或者for f in files一类的单一字符命名循环用的临时变量,即使是临时debug用。容易产生在程序中的混用,出错后不易查出

运算错误

四元数规范

  • 四元数有两种表示方式,不同模块返回的实部、虚部的顺序也可能不一样(如[w,x,y,z][x,y,z,w]),在使用时必须确认

浮点数精度

实例1:

  • 开平方的位置不同,使得实际储存的数值大于理论上应得的结果,带入其他函数后因输入越界出现错误 下例中最后一个b略大于1,导致acos(b)报错
# The inaccuracy of the floating point makes you not being able to calculate the correct angle between two vectors
from math import acos, sqrt
 
def angle_1(ux, vx, uy, vy):
    eq = (ux*vx+uy*vy)/(sqrt(ux**2+uy**2)*sqrt(vx**2+vy**2))
    return eq
 
def angle_2(ux, vx, uy, vy):
    eq = sqrt((ux*vx+uy*vy)**2/((ux**2+uy**2)*(vx**2+vy**2)))
    return eq
 
ux = 195
vx = 208
uy = -225
vy = -240
 
a = angle_1(195, 208, -225, -240)
b = angle_2(195, 208, -225, -240)
print('a: {0:.20f}'.format(a))
print('acos(a): {}'.format(acos(a)))
print('{0:.20f}'.format(b))
print('acos(b): {}'.format(acos(b)))
 
 
a = angle_1(287, 308, -82, -88)
b = angle_2(287, 308, -82, -88)
print('a: {0:.20f}'.format(a))
print('acos(a): {}'.format(acos(a)))
print('{0:.20f}'.format(b))
print('acos(b): {}'.format(acos(b)))

实例2:

  • 加法顺序不同导致计算产生误差

弱类型的数据类型模糊

实例

>>> import numpy as np
>>> a = np.uint16(3)
>>> a
3
>>> b = np.float64(3)
>>> a*b
9.0
>>> -a*b
<stdin>:1: RuntimeWarning: overflow encountered in scalar negative
196599.0
>>> type(-a*b)
<class 'numpy.float64'>

简化代码时不同方法实现同一目的的考虑

获得数据是否按预期顺序排列?

  • 问题:在一个图像中给定两个点,找出这两个点所确定的直线上所有的点(优先按、其次按顺序排列) 解法:确定直线方程,由直线方程找到其与图像边界的交点
    • 分情况讨论,从的较小值向较大值方向搜索
    • 通过cv2.line绘制一条直线,通过掩膜找出直线并收集其上所有点,当直线左低右高时,因为np.where是逐行枚举,相当于优先根据值排列,再根据排列
import cv2, copy, time, sys
sys.path.append('../../')
import numpy as np
from math import sqrt, sin, cos, pi, atan2
 
def display_img(img):
    cv2.imshow('image', img)
    show_window = True
    while show_window:
        k = cv2.waitKey(0) & 0xFF
        if k == 27:#ESC
            cv2.destroyAllWindows()
            show_window = False
 
def get_colors_from_colormap(colormap=cv2.COLORMAP_JET, num_colors=1280, rgb_output=False):
    gray_values = np.linspace(0, 255, num_colors, dtype=np.uint8)
    gray_image = gray_values.reshape(-1, 1)
    color_image = cv2.applyColorMap(gray_image, colormap)
    colors = color_image.reshape(-1, 3).tolist()
    
    return colors
 
def create_line_from_points():
    a, b, c = 0.0183, 1, -169.1284
    ## fix the ray starting point:
    all_edge_pts = []
 
    w, h = 1280, 720
    if abs(b) > 1e-5: 
        y_l=int(round( (-c)/b )) ## left, x=0
        if (0<=y_l) and (y_l < h):
            all_edge_pts.append([0,y_l])
        
        y_r=int(round( (-a*(w-1)-c)/b )) ## right, x=w-1
        if (0<=y_r) and (y_r < h):
            all_edge_pts.append([w-1, y_r])
 
    if abs(a) > 1e-5:
        x_t = int(round( (-c)/a )) ## top, y=0
        if (0<=x_t) and (x_t< w):
            all_edge_pts.append([x_t, 0])
        
        x_b = int(round( (-c-b*(h-1))/a )) ## bottom, y=h-1
        if (0<=x_b) and (x_b < w):
            all_edge_pts.append([x_b,h-1])
 
    edge_pts = list({(x,y) for x,y in all_edge_pts}) ## remove duplicated points
    if len(edge_pts) < 2:
        print("ERROR! Found less than 2 points!")
 
    temp_img = np.zeros((h,w), dtype=np.uint8)
    cv2.line(temp_img, edge_pts[0], edge_pts[1], 255, 1)
    ys, xs = np.where(temp_img==255)
    line = list(zip(xs,ys))
    sorted_line = copy.deepcopy(line)
    sorted_line.sort()
    return line, sorted_line
 
if __name__ == '__main__':
    line, sorted_line = create_line_from_points()
    img = np.full((720, 1280, 3), 255, dtype=np.uint8)
    colors =get_colors_from_colormap(num_colors=1280)
    for i in range(len(line)):
        j = line[i]
        k = sorted_line[i]
        cv2.circle(img, j, radius=1, color=colors[i], thickness=-1)
        cv2.circle(img, (k[0],k[1]+100), radius=1, color=colors[i], thickness=-1)
 
    display_img(img)