(1)在HSV颜色空间获取某地物颜色区间,并进行阈值分割
本文采用蓝色地物作为研究对象,注意不一定非要采用HSV进行分割,例如传统的阈值分割都行,只要能够区分地物和背景就行,但是鉴于正射地物的复杂性,故采用HSV阈值区间进行分割。
low和top就是在HSV颜色空间内,该地物颜色的最小值和最大值
::具体方法可以是:
将图像转为HSV格式读取并绘制,利用鼠标查询记录获取
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: LIFEI
@time: 2023/9/7 14:12
@file: test8.py
@project: pythonProject
@describe: CWNU
@# -------------------------------------------------(one)----------------------------------------------
@# -------------------------------------------------(two)----------------------------------------------
"""
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
import osBGR_img = cv.imread(r"D:\data\test_img\test8.png")
RGB_img = cv.cvtColor(BGR_img, cv.COLOR_BGR2RGB)
HSV_img = cv.cvtColor(BGR_img, cv.COLOR_BGR2HSV)
low = np.array([100, 60, 60])
top = np.array([130, 255, 255])
HSV_mask = cv.inRange(HSV_img, low, top)
# 将HSV_mask转为BGR格式
BGR_mask = cv.cvtColor(HSV_mask, cv.COLOR_BGR2RGB)
# 再将BGR_mask转为GRAY格式
GRAY_mask = cv.cvtColor(BGR_mask, cv.COLOR_RGB2GRAY)# 以HSV_img为掩膜文件,掩膜提取该掩膜文件下的原始影像区域
res = cv.bitwise_and(RGB_img, RGB_img, mask=HSV_mask)plt.figure('mask')
plt.subplot(131), plt.imshow(RGB_img), plt.title('ori_img')
plt.subplot(132), plt.imshow(BGR_mask), plt.title('mask_img')
plt.subplot(133), plt.imshow(res), plt.title('ori_mask_img')
(2)绘制地物真实轮廓
【1】利用cv.findContours和cv.drawContours对阈值分割图进行阈值分割
# findContours函数是获取图像的轮廓
# 参数值:与原图格式相同的掩膜文件、轮廓检索模式、轮廓近似方法、
# 返回值:轮廓、层次结构
contours, hierarchy = cv.findContours(np.uint8(GRAY_mask), cv.RETR_TREE, cv.CHAIN_APPROX_NONE)# cv.CHAIN_APPROX_NONE // cv.CHAIN_APPROX_SIMPLE
# drawContours函数是绘制轮廓
# 参数值:原始影像、轮廓线、轮廓内径、轮廓颜色、轮廓线宽
RGB_img1 = np.copy(RGB_img)
contours_img = cv.drawContours(RGB_img1, contours, -1, (255, 0, 0), 2)
【2】利用自定义函数剔除误差轮廓
# 获取轮廓线的面积并删除不符合的轮廓
def get_area_del_contour(contour):# 声明全局变量global delete_contour_img, tp_contourRGB_img2 = np.copy(RGB_img)# 开辟空间list_area = []list_contour = []for cnt in range(0, len(contour)):# 计算轮廓的面积area = cv.contourArea(contour[cnt])list_area.append(area)# 判断面积是否大于300if area > 200:# 将大于300的轮廓存贮list_contour.append(contour[cnt])# 转为元组tp_contour = tuple(list_contour)delete_contour_img = cv.drawContours(RGB_img2, tp_contour, -1, (255, 0, 0), 2)return delete_contour_img, tp_contour
(3)将不规则轮廓转为可旋转矩阵轮廓,并计算地物面积
【1】自定义函数1,转为规则轮廓
# introduce: 将轮廓的边框转换为旋转矩形
def box_handle(contour):global box_box_img, box_boxRGB_img3 = np.copy(RGB_img)box_list = []for i in range(0, len(contour)):rect_rect = cv.minAreaRect(del_contour[i])box_box = cv.boxPoints(rect_rect)box_box = [np.intp(box_box)]box_list.append(box_box)box_box_img = cv.drawContours(RGB_img3, box_box, 0, (255, 0, 0), 2)return box_box_img, box_list
【2】自定义函数2,计算并绘制面积
def draw_area(img,box_contour):global imfarea_list = []loc_list = []for i in range(0, len(box_contour)):area = cv.contourArea(np.array(box_contour[i]))area_list.append(area)loc = np.array(box_contour[i][0][0])loc_list.append(loc)imf = cv.putText(img, str(area*10), tuple(loc+10), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)return area_list, loc_list, imf
(4)主函数
if __name__ == '__main__':delete_contour_img = []tp_contour = []box_box_img = []box_box = []imf = []del_contour_img, del_contour = get_area_del_contour(contours)box_contour_img, box = box_handle(del_contour)area_box_img = np.copy(box_contour_img)area_base, location, area_img = draw_area(area_box_img, box)plt.figure('delete')plt.subplot(121), plt.imshow(contours_img), plt.title('undelete_contour img'), plt.axis('off')plt.subplot(122), plt.imshow(del_contour_img), plt.title('delete_contour img'), plt.axis('off')plt.figure('box')plt.imshow(box_contour_img), plt.title('box_contour img'), plt.axis('off')plt.figure('area')plt.imshow(area_img), plt.title('area_contour img'), plt.axis('off')plt.show()print('假设该图像的像元分辨率为10m')for area in area_base:print(str(area*10)+'平方米')