Laser stripe center extraction - Steger method python

Laser stripe center extraction - Steger method python

Steger

Steger's algorithm is one of the most widely used linear structured light fringe center extraction algorithms. It was proposed by Steger at the end of the twentieth century. Steger's algorithm is based on the Hessian matrix (see Equation 1-18) to obtain the normal direction of the light stripes in the image.
insert image description here
The normal direction of a point in the image is given by the eigenvector corresponding to the absolute value of the maximum eigenvalue of the Hessian matrix of the point, and the sub-pixel position of the center of the light stripe is obtained by finding the extreme point in the normal direction. g(x,y) is a two-dimensional Gaussian convolution kernel, which is used to highlight the gray distribution characteristics of light bars. z(x,y) is an image matrix with the same size as the 2D Gaussian kernel centered at the point (x,y) on the image. This method has the advantages of high precision and good robustness, but the process of calculating the directional derivative of the Hessian matrix for the image is huge, and the effect of real-time extraction of the center of the light fringe cannot be achieved. In addition, if the Gaussian kernel is unreasonably selected, the image information will be distorted.

python code

import cv2
import numpy as np
np.seterr(divide='ignore', invalid='ignore')


def Steger(img):
    """
    :param img: image
    :return: image/newimage
    :超参数选择:高斯核/阈值(默认200)
    """
    gray_origin = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # cv2.namedWindow("gray_origin",cv2.WINDOW_GUI_NORMAL)
    # cv2.imshow("gray_origin",gray_origin)
    # cv2.waitKey(5)
    gray = cv2.GaussianBlur(gray_origin,(5,5),0)
    Ix = cv2.Scharr(gray, cv2.CV_32F, 1, 0)
    Iy = cv2.Scharr(gray, cv2.CV_32F, 0, 1)
    Ixx = cv2.Scharr(Ix, cv2.CV_32F, 1, 0)
    Ixy = cv2.Scharr(Ix, cv2.CV_32F, 0, 1)
    Iyy = cv2.Scharr(Iy, cv2.CV_32F, 0, 1)
    Iyx = cv2.Scharr(Iy, cv2.CV_32F, 1, 0)
    # Hessian矩阵
    row = img.shape[0]
    col = img.shape[1]
    CenterPoint = []
    newimage = np.zeros((row, col), np.uint8)
    for i in range(col):
        for j in range(row):
            if gray_origin[j,i] > 100:
                hessian = np.zeros((2,2),np.float32)
                hessian[0,0] = Ixx[j,i]
                hessian[0,1] = Ixy[j,i]
                hessian[1,0] = Iyx[j,i]
                hessian[1,1] = Iyy[j,i]
                ret,eigenVal,eigenVec= cv2.eigen(hessian)
                nx, ny, fmaxD = 0.0, 0.0,0.0
                if ret:
                    #print(eigenVal.shape,eigenVec.shape)
                    if np.abs(eigenVal[0,0]>=eigenVal[1,0]):
                        nx = eigenVec[0,0]
                        ny = eigenVec[0,1]
                        famxD = eigenVal[0,0]
                    else:
                        nx = eigenVec[1, 0]
                        ny = eigenVec[1, 1]
                        famxD = eigenVal[1, 0]
                    t = -(nx * Ix[j, i] + ny * Iy[j, i]) / (
                                nx * nx * Ixx[j, i] + 2 * nx * ny * Ixy[j, i] + ny * ny * Iyy[j, i])
                    if np.abs(t*nx)<=0.5 and np.abs(t*ny)<=0.5:
                        CenterPoint.append([i,j])
    # cv2.namedWindow("Steger_origin",0)
    # cv2.imshow("Steger_origin",img)
    # cv2.waitKey(5)
    for point in CenterPoint:
        #cv2.circle(img,(point[0],point[1]),1,(0,0,225))
        img[point[1], point[0], :] = (0,0,255)
        newimage[point[1], point[0]] = 255
    # cv2.namedWindow("res", 0)
    # cv2.imshow("res",img)
    return img, newimage


def StegerPlus(img):
    gray_origin = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray_origin, (5, 5), 0, 0)
    Ix = cv2.Scharr(gray, cv2.CV_32F, 1, 0,)
    Iy = cv2.Scharr(gray, cv2.CV_32F, 0, 1)
    Ixx = cv2.Scharr(Ix, cv2.CV_32F, 1, 0)
    Ixy = cv2.Scharr(Ix, cv2.CV_32F, 0, 1)
    Iyy = cv2.Scharr(Iy, cv2.CV_32F, 0, 1)
    Iyx = cv2.Scharr(Iy, cv2.CV_32F, 1, 0)
    # Hessian矩阵
    row = gray_origin.shape[0]
    col = gray_origin.shape[1]
    CenterPoint = []
    newimage = np.zeros((row, col), np.uint8)
    for i in range(col):
        for j in range(row):
            if gray_origin[j, i] > 200:
                hessian = np.zeros((2, 2), np.float32)
                hessian[0, 0] = Ixx[j, i]
                hessian[0, 1] = Ixy[j, i]
                hessian[1, 0] = Iyx[j, i]
                hessian[1, 1] = Iyy[j, i]
                ret, eigenVal, eigenVec = cv2.eigen(hessian) # 返回特征值/特征向量
                print(cv2.eigen(hessian))
                lambda1 = 0.
                lambda2 = 0.
                # (nx, ny)--> 法线方向
                nx, ny, fmaxD = 0.0, 0.0, 0.0
                if ret:
                    # Hessian矩阵最大特征值 对应的特征向量 对应于光条的法线方向
                    if np.abs(eigenVal[0, 0]) >= np.abs(eigenVal[1, 0]):
                        lambda1 = eigenVal[1,0]
                        lambda2 = eigenVal[0,0]
                        nx = eigenVec[0, 0]
                        ny = eigenVec[0, 1]
                        # 最大的特征值
                        famxD = eigenVal[0, 0]
                    else:
                        lambda1 = eigenVal[0, 0]
                        lambda2 = eigenVal[1, 0]
                        nx = eigenVec[1, 0]
                        ny = eigenVec[1, 1]
                        famxD = eigenVal[1, 0]
                    if lambda1 < 15 and lambda2 <- 50:
                        t = -(nx * Ix[j, i] + ny * Iy[j, i]) / (
                              nx * nx * Ixx[j, i] + 2 * nx * ny * Ixy[j, i] + ny * ny * Iyy[j, i])
                        # Hessian矩阵最大特征值对应的特征向量对应于光条的法线方向
                        if np.abs(t * nx) <= 0.5 and np.abs(t * ny) <= 0.5:
                                #CenterPoint.append([i, j])
                            CenterPoint.append([i, j])
    # cv2.namedWindow("Steger_origin", 0)
    # cv2.imshow("Steger_origin", gray_origin)
    for point in CenterPoint:
        newimage[point[1], point[0]] = 255
        # cv2.circle(img, (point[0], point[1]), 1, 255)
        img[point[1], point[0], :] = (0, 0, 255)
    # cv2.namedWindow("res", 0)
    # cv2.imshow("res", img)
    return img, newimage


def test(filename):
    img = cv2.imread(filename)
    start = cv2.getTickCount()
    Steger(img)
    print("spend",(cv2.getTickCount()-start) / cv2.getTickFrequency())
    cv2.waitKey(0)

def test02(filename):
    print(filename)
    laser_bin = cv2.imread(filename)
    start = cv2.getTickCount()
    StegerPlus(laser_bin)
    print("spend", (cv2.getTickCount() - start) / cv2.getTickFrequency())
    cv2.waitKey(0)

# (1236, 1624)
# Average one image time:  2.2572644654570557
# fn = "./1.png"
# test02(fn)


if __name__ == '__main__':

    import time
    import os
    import tqdm

    image_path = "./Jay/images/"
    save_path = "./Jay/steger200/"
    if not os.path.isdir(save_path): os.makedirs(save_path)

    sum_time = 0
    for img in tqdm.tqdm(os.listdir(image_path)):
        image = cv2.imread(os.path.join(image_path, img))
        start_time = time.time()
        image_c, line = Steger(image)
        end_time = time.time()
        sum_time += end_time - start_time
        cv2.imwrite(os.path.join(save_path, img), image_c)
        cv2.imwrite(os.path.join(save_path, img.split('.')[0] + "_line.png"), line)
    average_time = sum_time / len(os.listdir(image_path))
    print("Average one image time: ", average_time)










Guess you like

Origin blog.csdn.net/CharmsLUO/article/details/123264012