firelab-general/ratio_pyrometry.py

233 lines
6.8 KiB
Python
Raw Permalink Normal View History

2022-10-06 00:13:40 -07:00
import math
2022-10-18 13:07:51 -07:00
from multiprocessing.sharedctypes import Value
2022-10-06 00:13:40 -07:00
import cv2 as cv
import numpy as np
from numba import jit
from skimage import measure
2022-10-06 00:13:40 -07:00
@jit(nopython=True)
2022-10-11 13:46:53 -07:00
def rg_ratio_normalize(
imgarr,
I_Darkcurrent,
f_stop,
exposure_time,
ISO,
MIN_TEMP,
2022-10-20 17:33:15 -07:00
MAX_TEMP,
2022-10-27 12:01:35 -07:00
eqn_scaling_factor,
2022-10-11 13:46:53 -07:00
):
2022-10-27 12:01:35 -07:00
"""
Get normalized G/R -> temperature data + list of all temperatures
"""
2022-10-12 19:29:39 -07:00
# copy image into new array & chop off alpha values (if applicable)
imgnew = imgarr.copy()[:,:,:3]
2022-10-27 12:01:35 -07:00
positive_temps = []
2022-10-06 00:13:40 -07:00
for i in range(len(imgarr)):
for j in range(len(imgarr[i])):
px = imgarr[i][j]
2022-10-11 13:46:53 -07:00
# normalize R & G pixels
g_norm = (px[1] - I_Darkcurrent) * (f_stop ** 2) / (ISO * exposure_time)
2022-10-12 19:29:39 -07:00
r_norm = (px[2] - I_Darkcurrent) * (f_stop ** 2) / (ISO * exposure_time)
2022-10-06 00:13:40 -07:00
# apply camera calibration func
2022-10-20 17:33:15 -07:00
temp_C = pyrometry_calibration_formula(g_norm, r_norm, default=MIN_TEMP) * eqn_scaling_factor
# remove pixels outside calibration range
2022-10-18 13:07:51 -07:00
if (MIN_TEMP != None and temp_C < MIN_TEMP) or (MAX_TEMP != None and temp_C > MAX_TEMP):
temp_C = MIN_TEMP
2022-10-27 12:01:35 -07:00
elif temp_C > MIN_TEMP:
positive_temps.append(temp_C)
2022-10-06 00:13:40 -07:00
2022-10-20 17:33:15 -07:00
# scale light intensity to calculated temperature
pix_i = scale_temp(temp_C, MIN_TEMP, MAX_TEMP)
2022-10-12 19:29:39 -07:00
imgnew[i][j] = [pix_i, pix_i, pix_i]
2022-10-27 12:01:35 -07:00
return imgnew, positive_temps
2022-10-06 00:13:40 -07:00
@jit(nopython=True)
2022-10-12 19:29:39 -07:00
def pyrometry_calibration_formula(i_ng, i_nr, default=24.0):
"""
Given the green-red ratio, calculates an approximate temperature
2022-10-12 19:29:39 -07:00
in Celsius. Defaults to room temperature if there's an error.
"""
2022-10-12 19:29:39 -07:00
try:
2022-10-16 15:46:26 -07:00
return (
2022-10-18 13:07:51 -07:00
(362.73 * math.log10(i_ng / i_nr) ** 3) +
(2186.7 * math.log10(i_ng / i_nr) ** 2) +
(4466.5 * math.log10(i_ng / i_nr)) +
2022-10-16 15:46:26 -07:00
3753.5
)
2022-10-12 19:29:39 -07:00
except:
return default
2022-10-06 00:13:40 -07:00
2022-10-20 17:33:15 -07:00
@jit(nopython=True)
def scale_temp(t, min, max):
"""
Scale pixel temperature (t) to light intensity given min & max temp.
"""
return (t - min) / (max - min) * 255
2022-10-11 13:46:53 -07:00
def ratio_pyrometry_pipeline(
file_bytes,
# camera settings
I_Darkcurrent: float,
exposure_time: float,
f_stop: float,
ISO: float,
# pyrometry config
MAX_TEMP: float,
2022-10-12 17:37:31 -07:00
MIN_TEMP: float,
smoothing_radius: int,
2022-10-20 17:33:15 -07:00
key_entries: int,
eqn_scaling_factor: float,
# firebrand detection
firebrand_min_intensity_threshold: float,
firebrand_min_area: float
2022-10-11 13:46:53 -07:00
):
2022-10-11 11:19:48 -07:00
# read image & crop
2022-10-11 13:46:53 -07:00
img_orig = cv.imdecode(file_bytes, cv.IMREAD_UNCHANGED)
# ---------------------------------------------------------
# -- Firebrand detection
# ---------------------------------------------------------
img = cv.copyMakeBorder(
img_orig,
20,
20,
20,
20,
cv.BORDER_CONSTANT,
value=0
)
retval, thresh_gray = cv.threshold(img, firebrand_min_intensity_threshold, 255, cv.THRESH_BINARY)
kernel = np.ones((7, 7), np.uint8)
image = cv.morphologyEx(thresh_gray, cv.MORPH_CLOSE, kernel, iterations=1)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
retval, gray = cv.threshold(gray, 0, 255, cv.THRESH_BINARY)
contours = measure.find_contours(array=gray, level=100)
def calculate_area(countour):
c = np.expand_dims(countour.astype(np.float32), 1)
c = cv.UMat(c)
return cv.contourArea(c)
individual_firebrands = []
for contour in contours:
if calculate_area(contour) > firebrand_min_area:
mask = np.zeros(img.shape[0:2], dtype='uint8')
cv.fillPoly(mask, pts=np.int32([np.flip(contour, 1)]), color=(255,255,255))
retval, mask = cv.threshold(mask, 0, 255, cv.THRESH_BINARY)
#apply the mask to the img
masked = cv.bitwise_and(img, img, mask=mask)
masked_ratio_rg, ptemps_indiv = rg_ratio_normalize(
masked,
I_Darkcurrent,
f_stop,
exposure_time,
ISO,
MIN_TEMP,
MAX_TEMP,
eqn_scaling_factor,
)
# build & apply smoothing conv kernel
k = []
for i in range(smoothing_radius):
k.append([1/(smoothing_radius**2) for i in range(smoothing_radius)])
kernel = np.array(k)
masked_ratio_rg = cv.filter2D(src=masked_ratio_rg, ddepth=-1, kernel=kernel)
# write colormapped image
masked_ratio_rg_jet = cv.applyColorMap(masked_ratio_rg, cv.COLORMAP_JET)
# Generate key
step = (MAX_TEMP - MIN_TEMP) / (key_entries-1)
temps = []
key_img_arr = [[]]
for i in range(key_entries):
res_temp = MIN_TEMP + (i * step)
res_color = scale_temp(res_temp, MIN_TEMP, MAX_TEMP)
temps.append(math.floor(res_temp))
key_img_arr[0].append([res_color, res_color, res_color])
key_img = np.array(key_img_arr).astype(np.uint8)
key_img_jet = cv.applyColorMap(key_img, cv.COLORMAP_JET)
tempkey = {}
for i in range(len(temps)):
c = key_img_jet[0][i]
tempkey[temps[i]] = f"rgb({c[2]}, {c[1]}, {c[0]})"
individual_firebrands.append({
"img_data": masked_ratio_rg_jet,
"legend": tempkey,
"ptemps": ptemps_indiv
})
2022-10-27 12:01:35 -07:00
img, ptemps = rg_ratio_normalize(
2022-10-11 13:46:53 -07:00
img_orig,
I_Darkcurrent,
f_stop,
exposure_time,
ISO,
MIN_TEMP,
2022-10-20 17:33:15 -07:00
MAX_TEMP,
2022-10-27 12:01:35 -07:00
eqn_scaling_factor,
2022-10-11 13:46:53 -07:00
)
2022-10-11 11:19:48 -07:00
# build & apply smoothing conv kernel
k = []
for i in range(smoothing_radius):
k.append([1/(smoothing_radius**2) for i in range(smoothing_radius)])
kernel = np.array(k)
img = cv.filter2D(src=img, ddepth=-1, kernel=kernel)
# write colormapped image
img_jet = cv.applyColorMap(img, cv.COLORMAP_JET)
# ---------------------------------------------------------
# -- Generate temperature key
# ---------------------------------------------------------
2022-10-11 11:19:48 -07:00
2022-10-12 19:29:39 -07:00
# Generate key
2022-10-12 21:22:33 -07:00
step = (MAX_TEMP - MIN_TEMP) / (key_entries-1)
2022-10-11 11:19:48 -07:00
temps = []
key_img_arr = [[]]
for i in range(key_entries):
2022-10-12 21:22:33 -07:00
res_temp = MIN_TEMP + (i * step)
2022-10-20 17:33:15 -07:00
res_color = scale_temp(res_temp, MIN_TEMP, MAX_TEMP)
2022-10-11 16:03:00 -07:00
temps.append(math.floor(res_temp))
2022-10-11 11:19:48 -07:00
key_img_arr[0].append([res_color, res_color, res_color])
key_img = np.array(key_img_arr).astype(np.uint8)
key_img_jet = cv.applyColorMap(key_img, cv.COLORMAP_JET)
tempkey = {}
for i in range(len(temps)):
c = key_img_jet[0][i]
2022-10-12 19:29:39 -07:00
tempkey[temps[i]] = f"rgb({c[2]}, {c[1]}, {c[0]})"
2022-10-11 13:46:53 -07:00
# original, transformed, legend
return img_orig, img_jet, tempkey, ptemps, individual_firebrands