Open sevenlayercookie opened 1 year ago
some working python code. this works great to measure the smallest gridlines. can even straighten images (adds just a bit of processing time). Just need to translate this to C#.
works by counting all pixels in each column of pixels, then uses Fourier to find repeating frequencies
NOTE: this still doesn't account for telemetry without gridlines main.py
import cv2
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq
import time
from image_straightener import straighten_image
start_time = time.time()
input = 'testImages/test.png'
# Load the image
image = cv2.imread(input)
#image = straighten_image(input)
#cv2.imwrite('straightened.png', straightened)
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Save the grayscale image
#cv2.imwrite('grayscale.png', gray)
# Apply Otsu's thresholding
#_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Apply fixed thresholding with a lower threshold value
threshold_value = 254 # You can adjust this value as needed
_, binary = cv2.threshold(gray, threshold_value, 255, cv2.THRESH_BINARY)
# Save the binary image
#cv2.imwrite('binary.png', binary)
# Convert binary image to NumPy array (if not already)
binary = np.array(binary)
# Count black pixels in each column
columnPixels = np.sum(binary == 0, axis=0)
# Count black pixels in each row
rowPixels = np.sum(binary == 0, axis=1)
# Plotting the column pixel counts
#plt.figure(figsize=(12, 6))
#plt.subplot(1, 2, 1)
#plt.plot(columnPixels, color='black')
#plt.title('Black Pixel Count per Column')
#plt.xlabel('Column Index')
#plt.ylabel('Number of Black Pixels')
# Save the column pixel count plot
#plt.savefig('column_pixel_count.png')
# Plotting the row pixel counts
#plt.subplot(1, 2, 2)
#plt.plot(rowPixels, color='black')
#plt.title('Black Pixel Count per Row')
#plt.xlabel('Row Index')
#plt.ylabel('Number of Black Pixels')
# Save the row pixel count plot
#plt.savefig('row_pixel_count.png')
#plt.tight_layout()
#plt.show()
# Perform FFT on the column pixel counts
column_fft = fft(columnPixels)
column_freq = fftfreq(len(columnPixels))
# Plot the magnitude of the FFT
plt.figure(figsize=(12, 6))
plt.plot(column_freq, np.abs(column_fft))
plt.title('Frequency Analysis of Column Pixel Counts')
plt.xlabel('Frequency')
plt.ylabel('Magnitude')
plt.grid(True)
plt.show()
# Save the frequency analysis plot
plt.savefig('frequency_analysis.png')
# Find the highest frequency of significant magnitude
magnitude = np.abs(column_fft)
half_length = len(magnitude) // 2 # only consider the first half of the spectrum
peak_idx = np.argmax(magnitude[1:half_length]) + 1 # ignore the zero frequency component
# Highest significant frequency
highest_frequency = column_freq[peak_idx]
print(f"Highest significant frequency: {highest_frequency}")
# Determine the number of columns in each cycle
if highest_frequency != 0:
cycle_length = 1 / highest_frequency
else:
cycle_length = np.inf
print(f"Number of columns in each cycle: {cycle_length}")
# this represents number of pixels per 0.04 ms (small box)
# so # of pixels per .2 ms (big box) = cycle_length * 5
# and # of pixels per second = cycle_length * 25
# pixels per ms = cycle_length / 0.04
print(f"Pixels per small box: {cycle_length}")
print(f"Pixels per big box: {cycle_length * 5}")
pixels_per_ms = cycle_length / 40
pixels_per_sec = pixels_per_ms * 1000
print(f"Pixels per second: {pixels_per_sec}")
print(f" ")
print(f"Pixels per ms: {pixels_per_ms}")
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Execution time: {elapsed_time} seconds")
image_straightener.py
import cv2
import numpy as np
def straighten_image(image_path, lines_overlay_path = 'detectedlines.png'):
# Load the image
image = cv2.imread(image_path)
# Convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Use Canny edge detection
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
# Detect lines using Hough Line Transform
lines = cv2.HoughLines(edges, 1, np.pi/180, 200)
# Draw the detected lines on the image
lines_image = image.copy()
if lines is not None:
for rho, theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv2.line(lines_image, (x1, y1), (x2, y2), (0, 0, 255), 2)
# Save the image with lines overlaid
cv2.imwrite(lines_overlay_path, lines_image)
# Find the angle of the lines
angle = 0
if lines is not None:
for rho, theta in lines[0]:
angle = (theta * 180 / np.pi) - 90 # Convert from radians to degrees and adjust angle
# Rotate the image to straighten it
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
rotated = cv2.warpAffine(image, M, (w, h))
return rotated
Likely can use OpenCV (Computer Vision)
Probably only feasible if an EKG with gridlines. Should be able to reasonably detect these straight lines.
Maybe should involve:
Things to look into: Hough Line Transform (OpenCV)
If no grid lines (such as telemetry):