python 如何检测和计算从这个图像棱镜的Angular ?

xtfmy6hx  于 2023-05-21  发布在  Python
关注(0)|答案(1)|浏览(115)

我目前正试图检测棱镜形状材料的边缘,并找到该形状的Angular 。
我有一个这样的原始图像:

我写了一个Python程序来检测勃艮第背景和灰色材料之间的边缘(代码如下所示),它检测边缘如下:

但我不知道如何从检测到的边缘找到Angular 。有什么想法吗

import glob
import cv2
import numpy as np
import ctypes
import math

def get_screen_resolution():
    user32 = ctypes.windll.user32
    return user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)

def process_photos():
    # Get the list of image files in the directory
    image_files = glob.glob("LEF_*.jpg")

    # Process each image file
    for image_file in image_files:
        process_image(image_file)

def process_image(image_file):
    # Load the image
    image = cv2.imread(image_file)

    # Convert the image to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Perform color-based segmentation to extract the burgundy regions
    lower_burgundy = np.array([0, 0, 100])  # Adjust the lower threshold for burgundy color
    upper_burgundy = np.array([100, 100, 255])  # Adjust the upper threshold for burgundy color
    mask = cv2.inRange(image, lower_burgundy, upper_burgundy)

    # Apply a Gaussian blur to the mask to reduce noise
    blurred_mask = cv2.GaussianBlur(mask, (5, 5), 0)

    # Perform Canny edge detection on the grayscale image
    edges_gray = cv2.Canny(gray, 50, 150)

    # Combine the edges with the burgundy regions using bitwise AND
    combined_edges = cv2.bitwise_and(edges_gray, blurred_mask)

    # Dilate the edges to enhance connectivity
    dilated = cv2.dilate(combined_edges, None, iterations=2)

    # Find contours of the edges
    contours, _ = cv2.findContours(dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Approximate the contours to straight lines
    lines = cv2.HoughLinesP(dilated, rho=1, theta=np.pi/180, threshold=100, minLineLength=100, maxLineGap=10)

    # Draw the lines on the original image
    if lines is not None:
        # Compute the mean line from the detected line segments
        mean_x1, mean_y1, mean_x2, mean_y2 = np.mean(lines[:, 0, :], axis=0, dtype=np.int32)

        # Draw the mean line
        cv2.line(image, (mean_x1, mean_y1), (mean_x2, mean_y2), (0, 255, 0), 2)

        # Compute the angle of the mean line
        angle = math.atan2(mean_y2 - mean_y1, mean_x2 - mean_x1) * 180 / np.pi
        print("Angle:", angle)

    # Draw the contours on the original image
    cv2.drawContours(image, contours, -1, (0, 255, 0), 2)

    # Resize the image to fit the screen resolution
    screen_width, screen_height = get_screen_resolution()
    image = cv2.resize(image, (screen_width, screen_height))

    # Display the processed image
    cv2.imshow("Processed Image", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

process_photos()
nnsrf1az

nnsrf1az1#

我尝试了一下,使用了一些不同的技术,这样你就可以使用、适应和合并你喜欢的任何方面。
值得注意的是,我使用了:

  • cv.inRange()来检测和分割勃艮第背景而不是cv.findContours()
  • 一个低通滤波器来平滑“岩石”边缘并找到圆锥的峰值,
  • 根据峰值位置将图像分割为两侧
  • 两边各有一条直线。
#!/usr/bin/env python3

import cv2 as cv
import numpy as np
from scipy import ndimage
import math

def lowpass(isignal, w):
   # Low pass filter
   # isignal is the input signal
   # osignal is the output signal
   # w is the window width that decides how many pixels affect the output
   kernel = np.lib.pad(np.linspace(1,3,w), (0,w-1), 'reflect') 
   kernel = np.divide(kernel,np.sum(kernel))
   osignal = ndimage.convolve(isignal, kernel) 
   return osignal

# Load image
im = cv.imread('mountain.jpg')
h, w = im.shape[:2]

# Convert to HSV and segment burgundy background
HSV = cv.cvtColor(im, cv.COLOR_BGR2HSV)

# Low and high HSV threshold for background
bglo = np.uint8([5,30,0])
bghi = np.uint8([30,255,255])
bg = cv.inRange(HSV, bglo, bghi)
# Save just for debug, easy cleanup with: rm DEBUG-*png
cv.imwrite('DEBUG-bg.png', bg)

# Get distance from top of image to first black pixel in each col
coltops = (bg!=255).argmax(axis=0)
# Get distance from bottom of last black pixel in each col
y = h - coltops

# Smooth the the curve, I chose image width/10 as the window size - you can experiment
ysmooth = lowpass(y, int(w/10))
for x in range(im.shape[1]):                             # illustration only - can be deleted
   # Plot smooth curve in red on top of original image   # illustration only - can be deleted
   im[h-ysmooth[x],x] = [0,0,255]                        # illustration only - can be deleted
cv.imwrite('DEBUG-smooth.png', im)                       # illustration only - can be deleted

# Now locate the x-coordinate of the peak of the smoothed curve to get the mountain centre
cx = ysmooth.argmax() # prints 792
print(f'DEBUG: x-coordinate of mountain centre is {cx}')

# Now split original (not smoothed) y-values into two separate lines - left and right side
yLeft = y[:cx]
yRight = y[cx:]

import matplotlib.pyplot as plt                                    # illustration only - can be deleted

# Fit straight line to left side
x = np.arange(len(yLeft))
a, b = np.polyfit(x, yLeft, 1)
angle = math.degrees(math.atan(a))
print(f'Left side: y = {a:0.3f} * x + {b:0.3f}, => angle: {angle:0.3f}')

# Plot the points
plt.scatter(x, yLeft, color='lime')                                # illustration only - can be deleted

# Draw line of best fit to plot
plt.plot(x, a*x+b, color='steelblue', linestyle='--', linewidth=2) # illustration only - can be deleted
plt.savefig('left.png')                                            # illustration only - can be deleted
plt.clf() # clear for right side                                   # illustration only - can be deleted

# Fit straight line to right side
x = np.arange(len(yRight))
a, b = np.polyfit(x, yRight, 1)
angle = math.degrees(math.atan(a))
print(f'Right side: y = {a:0.3f} * x + {b:0.3f}, => angle: {angle:0.3f}')

# Plot the points
plt.scatter(x, yRight, color='lime')                              # illustration only - can be deleted

# Draw line of best fit to plot
plt.plot(x, a*x+b, color='steelblue', linestyle='--', linewidth=2)# illustration only - can be deleted
plt.savefig('right.png')                                          # illustration only - can be deleted

您可以放心地忽略所有matplotlib.pyplot内容-这只是为了说明。
它输出如下:

Left side: y = 0.598 * x + 213.244, => angle: 30.873
Right side: y = -0.687 * x + 728.566, => angle: -34.492

分割的背景(DEBUG-bg.png)看起来像这样:

平滑的边(DEBUG-smooth.png)如下所示:

左右两边的图是这样的:

相关问题