云图-地基云图

云图-地基云图

地基云图介绍

云图预处理

云图障碍物清除

  • 手动标记障碍物掩码
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 大模型 机器学习和前后端的技术学习和分享
感谢大家的关注与支持!

相关推荐
ai_moe4 小时前
MapAnything: 通用前馈式度量3D重建
1024程序员节
tritone4 小时前
在优豆云免费云服务器上搭建与配置Apache的实践笔记
服务器·网络·apache·1024程序员节
RTC老炮4 小时前
webrtc弱网-PccNetworkController类源码分析与算法原理
网络·算法·webrtc
YongCheng_Liang4 小时前
Windows CMD 常用命令:7 大核心模块速查指南(附实战场景)
运维·服务器·windows·1024程序员节
CV实验室4 小时前
TPAMI 2025 | 从分离到融合:新一代3D场景技术实现双重能力提升!
人工智能·计算机视觉·3d
Swift社区4 小时前
LeetCode 406 - 根据身高重建队列
算法·leetcode·1024程序员节
敲上瘾4 小时前
背包dp——动态规划
c++·算法·动态规划
oe10194 小时前
CNCF Kepler与MCP:开启云原生绿色计算的人机协作新纪元
1024程序员节
野犬寒鸦4 小时前
从零起步学习MySQL || 第九章:从数据页的角度看B+树及MySQL中数据的底层存储原理(结合常见面试题深度解析)
java·服务器·数据库·后端·mysql·oracle·1024程序员节