云图-地基云图
地基云图介绍
云图预处理
云图障碍物清除
- 手动标记障碍物掩码
python
import cv2
import numpy as np
# ===== 初始化数据 =====
img = cv2.imread(img_path)
if img is None:
raise FileNotFoundError(f"无法读取文件 {img_path}")
fixed_window_size = (1000, 1000) # 窗口大小为800x600
img = cv2.resize(img, fixed_window_size)
clone = img.copy() # 原图备份
mask = np.zeros(img.shape[:2], dtype=np.uint8) # 单通道掩码
points = [] # 存储多边形点
# 鼠标回调:点击添加点
def click_event(event, x, y, flags, param):
global points, img
if event == cv2.EVENT_LBUTTONDOWN:
points.append((x, y))
# 在图上画一个小圆点标记点击位置
cv2.circle(img, (x, y), 3, (0, 0, 255), -1)
# 如果有两个及以上的点,就画折线
if len(points) > 1:
cv2.line(img, points[-2], points[-1], (0, 255, 0), 1)
# 右键:闭合多边形
elif event == cv2.EVENT_RBUTTONDOWN:
if len(points) > 2:
cv2.polylines(img, [np.array(points)], True, (255, 0, 0), 1)
cv2.fillPoly(mask, [np.array(points)], 255)
points.clear()
# 创建窗口
cv2.namedWindow('image')
cv2.setMouseCallback('image', click_event)
print("操作说明:\n"
" 左键点击:添加多边形顶点\n"
" 右键:闭合多边形并填充掩码\n"
" R 键:重置所有标注\n"
" S 键:保存掩码并退出\n"
" Esc 键:退出不保存\n")
while True:
cv2.imshow('image', img)
# cv2.imshow('mask', mask)
key = cv2.waitKey(1) & 0xFF
if key == ord('r'):
img = clone.copy()
mask[:] = 0
points.clear()
print("标注已重置。")
elif key == ord('s'):
cv2.imwrite(mask_save_path, mask)
print(f"掩码已保存到 {mask_save_path}")
break
elif key == 27: # ESC
break
cv2.destroyAllWindows()
云图圆心及边界处理
- 使用行列扫描法
python
def CloudCircularBboundary(img, T=40):
"""云图半径圆心坐标及有效区域裁剪"""
rows, cols = img.shape[:2]
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
top, bottom, left, right = 0, 0, 0, 0
# 从上向下扫描
for i in range(0, rows, 1):
for j in range(0, cols, 1):
if img_gray[i, j] >= T:
if img_gray[i + 1, j] >= T:
top = i
break
else:
continue
break
# 从下向上扫描
for i in range(rows - 1, -1, -1):
for j in range(0, cols, 1):
if img_gray[i, j] >= T:
if img_gray[i - 1, j] >= T:
bottom = i
break
else:
continue
break
# 从左向右扫描
for j in range(0, cols, 1):
for i in range(top, bottom, 1):
if img_gray[i, j] >= T:
if img_gray[i, j + 1] >= T:
left = j
break
else:
continue
break
# 从右向左扫描
for j in range(cols - 1, -1, -1):
for i in range(top, bottom, 1):
if img_gray[i, j] >= T:
if img_gray[i, j - 1] >= T:
right = j
break
else:
continue
break
# 计算有效区域半径
R = int(max((bottom - top) / 2, (right - left) / 2))
img_valid = img[top:int(top + 2 * R), left:int(left + 2 * R)]
# 创建掩膜(单通道)
h, w = img_valid.shape[:2]
x, y = w // 2, h // 2 # 中心
mask = np.zeros((h, w), dtype=np.uint8)
cv2.circle(mask, (x, y), R, 255, -1)
white_bg = np.ones_like(img_valid, dtype=np.uint8) * 255
# 把圆形区域的像素从原图复制到白背景上
result = white_bg.copy()
result[mask == 255] = img_valid[mask == 255]
return result, R, (x, y)
- 基于霍夫变换的云图边界检测
python
def CloudCircularBboundary(img):
"""云图圆形边界检测"""
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 250, 255)
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 20,
param1=50, param2=30, minRadius=0, maxRadius=0)
if circles is not None:
max_radius = 0
masked_img,selected_circle = None,None
circles = np.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
if r > max_radius:
max_radius = r
selected_circle = (x, y, r)
print("最大圆形:", selected_circle)
if selected_circle is not None:
# x, y, r = selected_circle
x, y, r = 300,300,250
mask = np.zeros(img.shape[:2], dtype="uint8")
cv2.circle(mask, (x, y), r, 255, -1)
masked_img = cv2.bitwise_and(img, img, mask=mask)
return masked_img,selected_circle,""
else:
return None,None,"未检测到圆形区域"
云图色度增强
python
def CloudChroma(img, B_coff=0.5, R_coff=0.5):
# 云图色度增强
R = img[:, :, 0].astype(np.float32)
G = img[:, :, 1].astype(np.float32)
B = img[:, :, 2].astype(np.float32)
BR_ratio = B - R
BR_mean = np.mean(BR_ratio)
diff = BR_ratio - BR_mean
R_enhanced = R.copy()
B_enhanced = B.copy()
B_enhanced += diff * B_coff
R_enhanced -= diff * R_coff
B_enhanced = np.clip(B_enhanced, 0, 255)
R_enhanced = np.clip(R_enhanced, 0, 255)
img_enhanced = np.stack([R_enhanced, G, B_enhanced], axis=2).astype(np.uint8)
return img_enhanced
云图太阳位置
python
def SolarPosition(img, dt, lat, lon, R: float, camera_angle: float = 0) -> Tuple[int, int, float, float]:
img_h, img_w = img.shape[:2]
z, a = SolarZenithAzimuth(lat, lon, dt)
r = (z / 90) * R
theta_rad = math.radians(a - camera_angle)
x0, y0 = img_w / 2, img_h / 2
x = x0 - r * math.sin(theta_rad)
y = y0 - r * math.cos(theta_rad)
return int(round(x)), int(round(y)), z, a
云图云层识别
云层识别方法
- RB
python
def RBR(img, R1, center, threshold=1.2):
B = img[:, :, 0]
R = img[:, :, 2]
BR_ratio = B / (R + 1e-6)
cloud_mask = (BR_ratio > threshold).astype(np.uint8) * 255 # 云为1,天空为0
mask = np.zeros_like(BR_ratio, dtype=np.uint8)
cv2.circle(mask, center, R1, 255, -1)
pixel_count = np.count_nonzero(mask) # 圆内全部像素点个数
cloud_count = np.count_nonzero(cloud_mask)
cloud_coverage = 1 - cloud_count / pixel_count
go_img = 255 - cloud_mask
go_img = cv2.bitwise_and(go_img, go_img, mask=mask)
return round(cloud_coverage, 2), go_img
def BRD(img, R1, center, threshold=1.2):
B = img[:, :, 0]
R = img[:, :, 2]
BR_ratio = B - R
cloud_mask = (BR_ratio > threshold).astype(np.uint8) * 255 # 云为1,天空为0
mask = np.zeros_like(BR_ratio, dtype=np.uint8)
cv2.circle(mask, center, R1, 255, -1)
pixel_count = np.count_nonzero(mask) # 圆内全部像素点个数
cloud_count = np.count_nonzero(cloud_mask)
cloud_coverage = 1 - cloud_count / pixel_count
go_img = cloud_mask
go_img = cv2.bitwise_and(go_img, go_img, mask=mask)
return round(cloud_coverage, 2), go_img
def NRBR(img, threshold=0.05):
img_float = img.astype(np.float32)
B = img_float[:, :, 0]
G = img_float[:, :, 1]
R = img_float[:, :, 2]
denominator = (R + B)
denominator[denominator == 0] = 1e-6
nrbr = abs(R - B) / denominator
cloud_mask = (nrbr < threshold).astype(np.uint8)
cloud_fraction = np.sum(cloud_mask) / cloud_mask.size * 100
return cloud_fraction, cloud_mask * 255
def CloudSegment_BRD_Diff(image, threshold=5):
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
b, g, r = cv2.split(image)
diff = cv2.subtract(b, cv2.max(r, g))
_, mask = cv2.threshold(diff, threshold, 255, cv2.THRESH_BINARY)
mask = 255 - mask
cloud_coverage = np.sum((mask > 0).astype(np.uint8)) / mask.size * 100
return round(cloud_coverage,2),mask
- RB Kmean
python
def CloudSegment_BRD_Kmeans(img,alpha=0.5):
# 云图色度增强
R = img[:, :, 0].astype(np.float32)
G = img[:, :, 1].astype(np.float32)
B = img[:, :, 2].astype(np.float32)
BR_ratio = B - R
BR_mean = np.mean(BR_ratio)
diff = BR_ratio - BR_mean
R_enhanced = R.copy()
B_enhanced = B.copy()
B_enhanced += diff * alpha
R_enhanced -= diff * alpha
B_enhanced = np.clip(B_enhanced, 0, 255)
R_enhanced = np.clip(R_enhanced, 0, 255)
img_enhanced = np.stack([R_enhanced, G, B_enhanced], axis=2).astype(np.uint8)
# K-Means云层检测
features = np.stack([R_enhanced, G, B_enhanced], axis=-1)
h_img, w_img, c_img = features.shape
features_2d = features.reshape(-1, 3) # 转为二维 (N, 3)
kmeans = KMeans(n_clusters=2, n_init=10, max_iter=1000)
labels = kmeans.fit_predict(features_2d)
labels_img = labels.reshape(h_img, w_img)
# 根据聚类中心亮度判断哪个是云(亮度大)
cloud_cluster = np.argmax(kmeans.cluster_centers_[:, 0])
cloud_mask = (labels_img == cloud_cluster).astype(np.uint8) * 255
cloud_coverage = 1
return cloud_coverage,cloud_mask
- RB GMM
python
def CloudSegment_GMM(img):
# 2. 转 HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV).astype(np.float32)
# 4. 取特征 这里选 S,V 作为聚类特征
features = hsv[..., 1:3] # shape = (H, W, 2)
h, w, _ = features.shape
features_2d = features.reshape(-1, 2)
# 5. 下采样加速
sample_idx = np.random.choice(features_2d.shape[0], size=5000, replace=False)
sample_features = features_2d[sample_idx]
# 6. 拟合高斯混合模型
gmm = GaussianMixture(n_components=2, covariance_type='full',
tol=1e-3, # 收敛阈值
reg_covar=1e-6, # 正则化参数
max_iter=200, # 最大迭代次数
n_init=5, # 运行次数取最好
init_params='kmeans', # 初始化方式
random_state=42
)
gmm.fit(sample_features)
# 7. 对全图预测
labels = gmm.predict(features_2d)
labels_img = labels.reshape(h, w)
# 通常云像素亮度高,所以可以判断哪个聚类均值的V值更高
cluster_means = []
for k in range(2):
cluster_means.append(np.mean(features_2d[labels == k, 1])) # 取V均值
cloud_label = np.argmax(cluster_means)
mask_cloud = (labels_img == cloud_label).astype(np.uint8) * 255
cloud_coverage = np.sum((mask_cloud > 0).astype(np.uint8)) / mask_cloud.size * 100
return round(cloud_coverage,2),mask_cloud
- Gray
python
def CloudGray(img, threshold=130):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, threshold, 255, cv2.THRESH_BINARY)
cloud_coverage = 1
return cloud_coverage,binary
云团矢量外推
仅个人笔记使用,感谢点赞关注
目前仅专注于 NLP 大模型 机器学习和前后端的技术学习和分享
感谢大家的关注与支持! 