Blur to Focus Image

Auto Focus a Video-       Identify the most focused frame

            This project will generate a video which contains a sequence of the same image from the most blurry to the most focused and back to the most blurry. Use this video as a test sample for the autofocus function to identify the most focused image frame in the video. The AutoFocus methods include Variance of absolute values of Laplacian and Sum Modified Laplacian.

Generate a video with the same focused image¶

            Use the VideoWriter to generate a video with the same focused image.

fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_path, fourcc, fps, (inputframe_width, inputframe_height))

for i in range(frame_qty):
        out.write(frameImg)

out.release()
cv2.destroyAllWindows()

Reference:
https://docs.opencv.org/3.4/dd/d43/tutorial_py_video_display.html

Generate progressive blurry images¶

            A focused image will go through a gradual blurring process to generate a sequence of images with the incremented Gaussian blurs.

The GaussianBlur algorithm convolves the source image with the specified Gaussian kernel to smooth the high contrast feature edges. Specify the width and height of the kernel which should be positive and odd. The Gaussian kernel standard diviation in both X and Y directions can also be specified.

Reference:
https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html

fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))

    kernel_size = 1
    while True:
        ret, frame = cap.read()
        if not ret:
            break
            
        if kernel_size <= max_kernel_size:
            blurred_frame = cv2.GaussianBlur(frame, (kernel_size, kernel_size), 0)
            out.write(blurred_frame)
            kernel_size += blur_increment
        else:
             out.write(cv2.GaussianBlur(frame, (max_kernel_size, max_kernel_size), 0))

    cap.release()
    out.release()
    cv2.destroyAllWindows()

Reverse the video with blurry images¶

Step 1. Collect all frames from the target video¶

frames = []
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        frames.append(frame)
    cap.release()

Step 2. Write the frames to a new video in a reversed order¶

            Simply apply the [reversed] command to the list of frames.

fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    if frames:
      height, width, _ = frames[0].shape
      out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))

      for frame in reversed(frames):
          out.write(frame)
      out.release()
    else:
        print("The video has no frames")

Step 3. Concatenate the three videos from blurry to focused to blurry¶

            Collect the three videos' file paths to a list. Read each target video name from the list and write to a single output video to concatenate the three videos.

video_captures = [cv2.VideoCapture(path) for path in video_paths]
    
fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # Codec 
output_writer = cv2.VideoWriter(output_path, fourcc, fps, (frame_width, frame_height))

# Iterate through each video and append its frames
for capture in video_captures:
    while(capture.isOpened()):
        ret, frame = capture.read()
        if ret:
            output_writer.write(frame)
        else:
            break
            
capture.release()
output_writer.release()
cv2.destroyAllWindows()

Identify the sharpest frame in the target video¶

            The goal of this project is to use the image filtering techniques to find the sharpest frame in the target video which goes from blurry to focuse to blurry.

Use a Laplacian operator to determine the sharp edge¶

            The Laplacian operator's elements were mapped with the pixel locations. The coefficients of the Lapacian operator can be used as kernel cell values corresponding to the pixel locations.

It equivalently measures the rate at which pixel intensity changes in an image such as edge detection.

\begin{equation} \frac{\partial^2 f}{\partial^2 x} = f(x+1, y)+f(x-1, y)-2 \times f(x,y) \end{equation}\begin{equation} \frac{\partial^2 f}{\partial^2 y} = f(x, y+1)+f(x, y-1)-2 \times f(x,y) \end{equation}

The Laplacian operator is
\begin{equation} \frac{\partial^2 f}{\partial^2 x} + \frac{\partial^2 f}{\partial^2 y} =f(x+1, y)+f(x-1, y)+f(x, y+1)+f(x, y-1)-4 \times f(x,y) \end{equation}

The image convolution kernel becomes:
\begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix}

            Use the variance of new values after convolution as a new focus measure. The variance value is used as a threshold to determine whether the image is blurry or sharp. The sharp image has a high variance value.

Reference:
https://www.researchgate.net/publication/3887632_Diatom_autofocusing_in_brightfield_microscopy_A_comparative_study

def LaplacianVariance(image):
    
    #Convert the color image to grayscale
    imgray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    
    #Calculate the laplacian matrix of the grayscale image
    lap = cv2.Laplacian(imgray, cv2.CV_32F, ksize = 3, 
                            scale = 1, delta = 0)
    
    #Calculate the variance at each pixel location
    delta = lambda t: (np.abs(t)-np.mean(np.abs(lap)))**2
    var_lap_array = np.array([delta(xi) for xi in lap])
    
    #Sum all variances
    return np.sum(var_lap_array)

Use a Sum Modified Laplacian technique to determine the contrast¶

            In the Laplacian operator, the second derivatives in the x and y directions can have opposite signs and result in cancellation of their values.

The Sum Modified Laplacian method uses the sum of the absolue values of the second derivatives.
The step variable specifies the spacing between target pixels.

\begin{equation} Modified \quad Laplacian =|\frac{\partial^2 f}{\partial^2 x}| + |\frac{\partial^2 f}{\partial^2 y}| =|f(x+step, y)+f(x-step, y)-2 \times f(x,y)|+|f(x, y+step)+f(x, y-step)-2 \times f(x,y)| \end{equation}

The focus measure is the sum of these modified Lapacian values, which are greater than a threshold value.

Reference:
https://cave.cs.columbia.edu/Statics/publications/pdfs/Nayar_TR89.pdf

def Modified_Laplacian(im):
    step=3
    thresh=7
    gy=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    (wx,wy)=gy.shape
    ML=[]
    for i in range(step,wx-step):
        for j in range(step,wy-step):
            sml=abs(2*gy[i,j]-gy[i-step,j]-gy[i+step,j])+ \
                     abs(2*gy[i,j]-gy[i,j-step]-gy[i,j+step])
            if sml>=thresh:
                ML.append(sml)
    
    return sum(ML)

Compute the Focus Measure of these two techniques for each image frame¶

Frame ID of the best frame [Variance of Absolute Laplacian]: 109
Frame ID of the best frame [Sum of Modified Laplacian]: 110

The identified best focused image frames are shown below:

End of File¶

In [ ]: