首页 > 解决方案 > How to extract an intensity profile along a line?

问题描述

Is there an out-of-the-box funcion in OpenCV to extract an intensity profile from an image along a line, something like the improfile function in MATLAB?

标签: pythonopencvimage-processing

解决方案


Here comes a small, interactive Python application to mimic MATLAB's improfile.

An image is loaded, and shown in an OpenCV window. Mouse button down and up events are recorded to get the line's start and end. The line (white) is shown in the image, and the corresponding RGB intensity profiles are shown in an addition Matplotlib window. The infinite loop can be exited by pressing the c key within the OpenCV window.

Here's how it looks:

Example 1

Example 2

And, here comes the code:

import cv2
from matplotlib import pyplot as plt
import numpy as np
from skimage import draw

# Actual mouse callback function
def print_coords(event, x, y, flags, param):

    # Global variables needed
    global image, image_copy, r_start, c_start

    # If left mouse button is clicked, start of line
    if (event == cv2.EVENT_LBUTTONDOWN):
        r_start = x
        c_start = y

    # If left mouse button is clicked, end of line; plot intensity profile
    if (event == cv2.EVENT_LBUTTONUP):
        r_end = x
        c_end = y
        image = cv2.line(image_copy.copy(), (r_start, c_start), (r_end, c_end), (255, 255, 255), 2)
        line = np.transpose(np.array(draw.line(r_start, c_start, r_end, c_end)))
        data = image_copy.copy()[line[:, 1], line[:, 0], :]
        plt.close()
        plt.figure('Intensity profile')
        plt.plot(data[:, 0], 'b', data[:, 1], 'g', data[:, 2], 'r')
        plt.draw()
        plt.pause(0.001)
        plt.legend(['Blue', 'Green', 'Red'])
        plt.ylim((0, 255))

# Read an image
image = cv2.imread('path/to/your/image.png', cv2.IMREAD_COLOR)
image_copy = image.copy()

# Set up window and mouse callback function
cv2.namedWindow("image")
cv2.setMouseCallback("image", print_coords)

# Loop until the 'c' key is pressed
while True:

    # Display image; wait for keypress
    cv2.imshow("image", image)
    key = cv2.waitKey(1) & 0xFF

    # If 'c' key is pressed, break from loop
    if  key == ord("c"):
        break

cv2.destroyAllWindows()

To get the coordinates of the line, I use the line function from scikit-image. That seems to be fastest Pythonic way.

Hope that helps the Python people looking for such a functionality!


推荐阅读