使用Python计算光伏组件数量,附完整代码

引言

随着可再生能源的普及,光伏组件在太阳能发电中的应用越来越广泛。在某些场景下,如光伏电站的维护或光伏板的安装检查,需要快速准确地计算光伏组件的数量。本文将介绍如何使用Python结合计算机视觉技术来实现这一目标。

文章目的

本篇文章旨在指导读者如何使用Python编程语言,通过图像处理技术自动识别并计算光伏组件的数量。

 环境准备

- 安装Python环境。
- 安装OpenCV库,用于图像处理。
- 安装matplotlib库,用于图像展示。

Python代码实现

1. **导入所需库**  
   首先,导入OpenCV、NumPy和matplotlib库。

2. **读取图片**  
   使用OpenCV的`imread`函数读取包含光伏组件的图片。

3. **颜色空间转换**  
   将图片从BGR颜色空间转换到HSV颜色空间,以便于后续的颜色分割。

4. **创建滑动条**  
   创建用于调整H、S、V值的滑动条,以确定光伏组件的颜色阈值。

5. **颜色分割**  
   根据滑动条的值,使用颜色阈值进行分割,提取光伏组件区域。

6. **边缘提取**  
   对分割后的图像使用Canny算法进行边缘提取。

7. **腐蚀与膨胀**  
   通过腐蚀和膨胀操作去除噪声和不必要的细节。

8. **滤波**  
   使用高斯滤波进一步平滑图像。

9. **轮廓查找**  
   使用`findContours`函数查找图像中的所有轮廓。

10. **多边形逼近**  
    对每个轮廓使用多边形逼近,以简化轮廓形状。

11. **面积计算与过滤**  
    计算每个轮廓的面积,并根据面积大小和轮廓顶点数过滤出光伏组件。

12. **显示结果**  
    在原始图片上绘制出识别的光伏组件,并显示组件数量。

代码逻辑

1. **读取与显示图片**  
   读取光伏组件的图片,并显示原始图片。

2. **颜色空间转换**  
   将图片从BGR转换到HSV,便于颜色分割。

3. **颜色分割**  
   通过用户调整的H、S、V值,使用`inRange`函数进行颜色分割。

4. **边缘提取**  
   使用Canny算法提取光伏组件的边缘。

5. **形态学操作**  
   通过腐蚀和膨胀操作去除小的噪声点。

6. **滤波**  
   使用高斯滤波进一步平滑图像,去除细节噪声。

7. **轮廓识别**  
   识别图像中的所有轮廓。

8. **多边形逼近与过滤**  
   对轮廓进行多边形逼近,并根据面积和顶点数过滤出光伏组件。

9. **计算数量**  
   统计并显示光伏组件的数量。

结语

通过上述步骤,我们可以使用Python和OpenCV库来计算光伏组件的数量。这种方法可以快速地处理大量图片,为光伏电站的维护和管理提供便利。希望本文能够帮助到对光伏组件计数感兴趣的读者。如果有任何问题或建议,欢迎在评论区留言讨论。

# 导入所需的库
import cv2
import numpy as np
import matplotlib
matplotlib.use('Qt5Agg') # 指定使用"Qt5Agg"后端
import matplotlib.pyplot as plt

# 读取图片
img = cv2.imread('C:\\12.jpg')
print('已读取图片,图片尺寸为:', img.shape)
cv2.imshow('原始图片', img)
cv2.waitKey(0)

# 转换到HSV颜色空间
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
print('已转换到HSV颜色空间')
cv2.imshow('HSV图片', hsv)
cv2.waitKey(0)

# 创建一个窗口,用来显示结果
cv2.namedWindow('result')

# 初始化mask为空数组
mask = np.array([])

# 定义一个回调函数,用来处理滑动条的变化
def on_trackbar(val):
    # 声明mask是全局变量
    global mask
    # 获取滑动条的位置
    h = cv2.getTrackbarPos('h', 'result')
    s = cv2.getTrackbarPos('s', 'result')
    v = cv2.getTrackbarPos('v', 'result')
    # 根据滑动条的位置设置颜色阈值
    lower = np.array([h, s, v])
    upper = np.array([180, 255, 255])
    # 颜色分割,提取光伏板区域
    mask = cv2.inRange(hsv, lower, upper)
    res = cv2.bitwise_and(img, img, mask=mask)
    print('已进行颜色分割,提取光伏板区域')
    # 显示结果
    cv2.imshow('result', res)

# 创建三个滑动条,分别控制H、S、V通道的最小值
cv2.createTrackbar('h', 'result', 0, 179, on_trackbar)
cv2.createTrackbar('s', 'result', 0, 255, on_trackbar)
cv2.createTrackbar('v', 'result', 0, 255, on_trackbar)
# 调用回调函数,更新mask的值
on_trackbar(0)
# 等待用户按键退出
cv2.waitKey(0)
cv2.destroyAllWindows()
# 边缘提取,采用Canny算子
edges = cv2.Canny(mask, 100, 200)
print('已进行边缘提取,采用Canny算子')
cv2.imshow('边缘提取图片', edges)
cv2.waitKey(0)
# 创建一个窗口,用来显示结果
cv2.namedWindow('processed')
# 定义一个新的回调函数,用来处理滑动条的变化
def on_trackbar_2(val):
    # 获取滑动条的位置
    k = cv2.getTrackbarPos('k', 'processed')
    e = cv2.getTrackbarPos('e', 'processed')
    d = cv2.getTrackbarPos('d', 'processed')
    s = cv2.getTrackbarPos('s', 'processed')
    # 根据滑动条的位置设置腐蚀膨胀、滤波和按位与操作的参数
    kernel = np.ones((k, k), np.uint8) # kernel的大小为k*k
    global edges_1 # 声明edges_1是全局变量
    edges_1 = cv2.erode(edges, kernel, iterations=e) # 腐蚀e次
    edges_1 = cv2.dilate(edges_1, kernel, iterations=d) # 膨胀d次
    # 判断k是否为偶数,如果是的话,就加1变成奇数
    if k % 2 == 0:
        k += 1
    edges_1 = cv2.GaussianBlur(edges_1, (k, k), s) # sigma值为s
    edges_1 = cv2.bitwise_and(edges_1, mask)
    print('已进行腐蚀膨胀、滤波和按位与操作,去除噪声和细节')
    # 显示结果
    cv2.imshow('processed', edges_1)
# 创建四个滑动条,分别控制kernel的大小、腐蚀的次数、膨胀的次数和sigma值
cv2.createTrackbar('k', 'processed', 1, 10, on_trackbar_2)
cv2.createTrackbar('e', 'processed', 0, 10, on_trackbar_2)
cv2.createTrackbar('d', 'processed', 0, 10, on_trackbar_2)
cv2.createTrackbar('s', 'processed', 0, 10, on_trackbar_2)
# 调用回调函数,更新edges_1的值
on_trackbar_2(0)
# 等待用户按键退出
cv2.waitKey(0)
cv2.destroyAllWindows()
# 轮廓查找,多边形逼近和面积计算
# 把mask改成edges_1
contours, hierarchy = cv2.findContours(edges_1, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
count = 0 # 光伏板的数目

# 创建一个窗口,用来显示结果
cv2.namedWindow('contours')

# 在回调函数之外,先把原始图片保存为一个变量
original_img = cv2.imread('C:\\12.jpg')
# 在回调函数之外,先把原始图片的副本保存为一个变量
img_copy = original_img.copy()

# 定义一个新的回调函数,用来处理滑动条的变化
def on_trackbar_3(val):
    # 获取滑动条的位置
    e = cv2.getTrackbarPos('e', 'contours')
    # 根据滑动条的位置设置多边形逼近的epsilon值
    epsilon = e / 1000 # epsilon值为e/1000
    # 遍历所有轮廓
    for cnt in contours:
        # 多边形逼近,获取轮廓的顶点数
        approx = cv2.approxPolyDP(cnt, epsilon, True)
        # 面积计算,过滤掉太小或太大的轮廓
        area = cv2.contourArea(cnt)
        # 计算轮廓的长宽比
        x, y, w, h = cv2.boundingRect(cnt)
        ratio = w / h
        # 只有当面积在一定范围内,并且顶点数在4到6之间,并且长宽比在0.8到1.2之间时,才认为是光伏板
        if area > 1000 and area < 100000 and 4 <= len(approx) <= 6 and 0.8 <= ratio <= 1.2:
            # 绘制轮廓和顶点数
            # 把img变量赋值为原始图片的副本,以便重新绘制轮廓
            img = img_copy # 使用之前保存的副本
            cv2.drawContours(img, [approx], 0, (0, 0, 255), 2)
            cv2.putText(img, str(len(approx)), (approx[0][0][0], approx[0][0][1]), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
            # 数目加一
            global count # 声明count是全局变量
            count += 1

    # 显示结果
    print('已进行轮廓查找,多边形逼近和面积计算')
    print('光伏板的数目是:', count)
    cv2.imshow('contours', img)
    # 把count变量赋值为0,以便下次重新计算
    # 在回调函数之内赋值为0,而不是在回调函数之外
    count = 0

# 创建一个滑动条,控制多边形逼近的epsilon值
cv2.createTrackbar('e', 'contours', 10, 100, on_trackbar_3)

# 调用回调函数,更新img的值
on_trackbar_3(10)

# 等待用户按键退出
cv2.waitKey(0)
cv2.destroyAllWindows()

  • 31
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wh3933

你的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值