File size: 8,032 Bytes
a70a066 c171d38 0b71d57 a0b0f50 6896642 3c6dc95 b5ac1c2 0b71d57 760b53b b5ac1c2 760b53b b5ac1c2 760b53b b5ac1c2 760b53b b5ac1c2 760b53b b5ac1c2 760b53b b5ac1c2 760b53b 0b71d57 9820fad a0b0f50 2d07b10 b12ba5d 2d07b10 a0b0f50 d938147 8458a1c 2d07b10 81ba37c 9820fad 2d07b10 8458a1c 15b4c14 a0b0f50 81ba37c acb7cc3 b950b3d a0b0f50 0b71d57 a9b013c 8458a1c a9b013c 8458a1c a9b013c 0b71d57 6896642 82e6cc4 6896642 6fa13e0 6896642 6fa13e0 6896642 c78eab8 6fa13e0 18b0f3c 6896642 d83fd16 6896642 2d07b10 0b71d57 acb7cc3 2d07b10 acb7cc3 81ba37c 3c6dc95 2d07b10 9820fad 3c6dc95 a0b0f50 acb7cc3 2d07b10 9820fad 2d07b10 6896642 2d07b10 9820fad 0b71d57 2d07b10 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | import gradio as gr
import numpy as np
import plotly.graph_objs as go
from scipy.ndimage import convolve
from gradio_imageslider import ImageSlider
import cv2
import os
# def readRAW(path):
# arr = np.fromfile(path, dtype=np.int16).reshape(96,240,256)
# # 将最后一维重塑为 (-1, 2),其中 -1 自动计算为 128
# reshaped = arr.reshape(*arr.shape[:-1], -1, 2)
# # 交换每一对中的两个元素
# swapped = reshaped[..., :, ::-1]
# # 恢复原始形状
# histogram_data = swapped.reshape(arr.shape)
# # 定义映射顺序:对每组8行进行调换
# mapping = [0, 4, 1, 5, 2, 6, 3, 7]
# # 每组包含的行数
# group_size = 8
# num_groups = 12 # 96/8
# # 创建一个用于存储结果的数组(也可以原地修改)
# output = np.empty_like(histogram_data)
# # 对每个 group 分别进行行重排
# for g in range(num_groups):
# start = g * group_size
# end = start + group_size
# output[start:end,:,:] = histogram_data[start:end,:,:][mapping,:,:]
# return output
def mipi_raw10_to_raw8_scaled(raw10_data):
raw10_data = np.frombuffer(raw10_data, dtype=np.uint8)
n_blocks = len(raw10_data) // 5
raw10_data = raw10_data[:n_blocks * 5].reshape(-1, 5)
p0 = (raw10_data[:, 0].astype(np.uint16) << 2) | ((raw10_data[:, 4] >> 0) & 0x03)
p1 = (raw10_data[:, 1].astype(np.uint16) << 2) | ((raw10_data[:, 4] >> 2) & 0x03)
p2 = (raw10_data[:, 2].astype(np.uint16) << 2) | ((raw10_data[:, 4] >> 4) & 0x03)
p3 = (raw10_data[:, 3].astype(np.uint16) << 2) | ((raw10_data[:, 4] >> 6) & 0x03)
raw8_data = np.empty((n_blocks * 4 * 2,), dtype=np.uint8)
raw8_data[0::8] = p0 & 0xFF
raw8_data[1::8] = p0 >> 8
raw8_data[2::8] = p1 & 0xFF
raw8_data[3::8] = p1 >> 8
raw8_data[4::8] = p2 & 0xFF
raw8_data[5::8] = p2 >> 8
raw8_data[6::8] = p3 & 0xFF
raw8_data[7::8] = p3 >> 8
return raw8_data.tobytes()
def readRAW(path):
filesize = os.path.getsize(path)
with open(path, "rb") as f:
raw_data = f.read()
# Case 1: 如果是 MIPI RAW10 格式,大小为 7,372,800 字节
if filesize == 7372800:
raw_data = mipi_raw10_to_raw8_scaled(raw_data)
# 转换为 int16 并 reshape
arr = np.frombuffer(raw_data, dtype=np.int16).reshape(96, 240, 256)
# Byte Swap: [x,y,256] → [x,y,128,2] → swap last dim → [x,y,256]
reshaped = arr.reshape(*arr.shape[:-1], -1, 2)
swapped = reshaped[..., ::-1]
histogram_data = swapped.reshape(arr.shape)
# Line remapping (每组8行:0,4,1,5,...)
mapping = [0, 4, 1, 5, 2, 6, 3, 7]
group_size = 8
num_groups = 12 # 96 / 8
output = np.empty_like(histogram_data)
for g in range(num_groups):
start = g * group_size
end = start + group_size
output[start:end, :, :] = histogram_data[start:end, :, :][mapping, :, :]
return output
def load_bin(file, threshold=3):
raw_hist = readRAW(file.name)
multishot = (raw_hist[..., 254] * 1024 + raw_hist[..., 255]).astype(np.float32)
normalize_data = 12000 / multishot
nor_hist = raw_hist * normalize_data[..., np.newaxis]
img = np.sum(nor_hist[:, :, :-2], axis=2)
norm_img = (img - img.min()) / (img.max() + 1e-8)
img_uint8 = (norm_img * 255).astype(np.uint8)
img_zoomed = np.repeat(np.repeat(img_uint8, 4, axis=0), 4, axis=1)
depth_slider_imgs = plot_depth(nor_hist,threshold) # 👈 直接在这里计算
return img_zoomed, raw_hist, nor_hist, depth_slider_imgs
def plot_pixel_histogram(evt: gr.SelectData, raw_hist, nor_hist):
# print("evt:", evt)
x, y = evt.index # Gradio SelectData 对象
x = x // 4
y = y // 4
raw_values = raw_hist[y, x, :]
nor_values = nor_hist[y, x, :]
fig = go.Figure()
fig.add_trace(go.Scatter(y=raw_values, mode="lines+markers"))
fig.update_layout(
title=f"Pixel ({x}, {y}) 在所有 {raw_values.shape[0]} 帧的强度变化",
xaxis_title="帧索引 (T)",
yaxis_title="强度值",
)
return fig
def to_uint8_image(arr):
norm = (arr) / (np.max(arr) + 1e-8)
return (norm * 255).astype(np.uint8)
def plot_depth(norm_hist, threshold):
tof = np.argmax(norm_hist[...,:-5], axis=2)
img_tof = to_uint8_image(tof)
noise = np.median(norm_hist[...,:8],axis=2)
noise_th = noise + 4 * np.sqrt(noise)
norm_hist_sub_noise = norm_hist - noise_th[...,np.newaxis]
# norm_hist = norm_hist
norm_hist_sub_noise[norm_hist_sub_noise<0]=0
norm_hist_pool = norm_hist_sub_noise[::10,::10,:]
print(norm_hist_pool.shape)
lst_scatter_th = []
for idx in range(0,256):
map = norm_hist_pool[...,idx]
ratio = 1/np.max(map) * 255
map_ratio = map * ratio
_, otsu_thresh = cv2.threshold(map.astype(np.uint8), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_TRIANGLE)
# _, otsu_thresh = cv2.threshold(map_ratio.astype(np.uint8), 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
lst_scatter_th.append(_/ratio)
de_scatter = norm_hist_sub_noise - np.array(lst_scatter_th)[np.newaxis, np.newaxis, :]
de_scatter[de_scatter<0]=0
# de_scatter = norm_hist
tof = np.argmax(de_scatter[...,:-5], axis=2)
peak = np.max(de_scatter[...,:-5], axis=2)
r = 4
neighbor_score = 16
snr_th = 0.1
for y in range(norm_hist.shape[0]):
for x in range(norm_hist.shape[1]):
t = tof[y,x]
shift = np.argmax(norm_hist[y,x,max(0,t-r):min(255,t+r+1)]) -r
t = t + shift
cubic_S = de_scatter[max(0,y-1):min(norm_hist.shape[0],y+2), max(0,x-1):min(norm_hist.shape[1],x+2), max(0,t-1):min(255,t+2)]
cubic_SN = norm_hist[max(0,y-1):min(norm_hist.shape[0],y+2), max(0,x-1):min(norm_hist.shape[1],x+2), max(0,t-1):min(255,t+2)]
snr = cubic_S/np.sqrt(cubic_SN + 1e-6)
# print(shift)
mask = snr> snr_th
if abs(shift) <= r and np.sum(mask) > neighbor_score:
tof[y,x] = t
else:
tof[y,x] = 0
def get_value_at_depth_index(array_3d, depth_index):
return array_3d[np.arange(array_3d.shape[0])[:, None], np.arange(array_3d.shape[1]), depth_index]
C3 = get_value_at_depth_index(norm_hist,tof-1)
C4 = get_value_at_depth_index(norm_hist,tof)
C5 = get_value_at_depth_index(norm_hist,tof+1)
shift_mat = (C5-C3)/(4.0 * C4 -2.0 * C3 - 2.0 * C5 + 1e-6)
mask = abs(shift_mat) < 1
shift_mat = shift_mat * mask
tof[tof<0]=0
img_filter = to_uint8_image(tof)
colored_tof = cv2.applyColorMap(img_tof, cv2.COLORMAP_VIRIDIS)[:, :, ::-1]
colored_tof_filter = cv2.applyColorMap(img_filter, cv2.COLORMAP_VIRIDIS)[:, :, ::-1]
return [colored_tof, colored_tof_filter]
# return [img_ref, img_ref_filter]
with gr.Blocks() as demo:
gr.Markdown("## 上传 96×240×256 int16 `.bin/.raw` 文件,点击图像像素查看该像素的 256 帧直方图")
file_input = gr.File(label="上传 .raw/.bin 文件", file_types=[".raw", ".bin"])
image_display = gr.Image(interactive=True, label="点击像素显示强度曲线")
histogram = gr.Plot(label="像素强度曲线")
depth_image_slider = ImageSlider(label="Filter Depth Map with Slider View", elem_id='img-display-output', position=0.5)
threshold_slider = gr.Slider(1, 30, value=3, step=1, label="Mask 阈值设定 (ref > x)")
raw_hist = gr.State()
nor_hist = gr.State()
# 单一入口统一触发
file_input.change(
load_bin,
inputs=[file_input,threshold_slider],
outputs=[image_display, raw_hist, nor_hist, depth_image_slider]
)
image_display.select(
plot_pixel_histogram,
inputs=[raw_hist, nor_hist],
outputs=histogram
)
threshold_slider.change(
load_bin,
inputs=[file_input,threshold_slider],
outputs=[image_display, raw_hist, nor_hist, depth_image_slider])
demo.launch()
|