最近开始接触图像处理,接到的首个任务就是将实验室用颜色标记好的数据再在原图上按不同颜色框出来,以在模型预测阶段检查预测效果。下面使用一张摇滚乐队Halestrom的图片进行说明。
首先,我拿到的原图如下图所示:
def detect_color(img_path, mark_img_path):
"""检测一张图片中的不同颜色区域"""
image = cv2.imread(img_path) # 加载图片
# 定义颜色范围,这里可以根据自己的需求定义,注意这里颜色定义的顺序是BGR
boundaries = [
([0, 0, 255], [0, 0, 255]), # 红色
([0, 255, 0], [0, 255, 0]), # 绿色
([255, 0, 0], [255, 0, 0]) # 蓝色
# 遍历颜色范围
for (lower, upper) in boundaries:
# 由颜色范围创建NumPy数组
lower = np.array(lower, dtype="uint8")
upper = np.array(upper, dtype="uint8")
# 根据特定颜色范围创建mask
mask = cv2.inRange(image, lower, upper)
output = cv2.bitwise_and(image, image, mask=mask)
mark_zone_with_color(output, mark_img_path, lower)
def mark_zone_with_color(src_img, mark_img, mark_color):
"""根据颜色在原始图像上标记区域"""
# 转灰度图片
gray = cv2.cvtColor(src_img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY) # ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) 则只能绘制出平地轮廓
# 轮廓检测
_, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
newImg = cv2.imread(mark_img)
newImg = cv2.resize(newImg, (512, 512))
for i in range(len(contours)-1):
cv2.drawContours(image=newImg, contours=contours[i+1], contourIdx=-1, color=tuple(mark_color.tolist()), thickness=2, maxLevel=1, lineType=8)
cv2.imwrite(mark_img, newImg)
def batch_marker(src_img_dir, draw_contours_img_dir):
批处理需要标记的图像,注意这里默认原始图像和标记了颜色区块的图像
是同名的,但是放在不同的文件夹里。
src_imgs = get_filenames_in_dir(src_img_dir)
dc_imgs = get_filenames_in_dir(draw_contours_img_dir)
for src in src_imgs:
for dc in dc_imgs:
if src == dc:
detect_color(os.path.join(src_img_dir, src), os.path.join(draw_contours_img_dir, dc))
def get_filenames_in_dir(dir):
"""获取一个目录下所有文件的文件名"""
for root, dirs, files in os.walk(dir):
return files
使用时直接调用detect_color函数就可以了,第一个参数是像图2一样的图片路径,第二个参数是像图1一样的原始图片的路径。
opencv是经常会被使用到的图像处理库,下面介绍一下上述代码中使用到的几个关键函数。
inRange(src, lowerb, upperb[, dst]) -> dst
参数含义:src:输入源图像。
lowrb:需要检测图像像素范围的下阈值。
upperb:需要检测图像像素范围的上阈值。
dst:输出图像数组,形状和输入图像src一致,CV_8U类型。
功能:将图像中的像素在lowrb和upperrb范围内的设置成255,范围之外的设置成0以输出。
cvtColor(src, code[, dst[, dstCn]]) -> dst
参数含义:src:输入源图像。
code:图像编码方式或者是颜色空间。
功能:将图像从一个颜色空间转换到另外一个颜色空间,通常是将BGR图像转换为灰度图。
threshold(src, thresh, maxval, type[, dst]) -> retval, dst
参数含义:src:输入源图像。
thresh:阈值。
maxval:用于THRESH_BINARY和THRESH_BINARY_INV阈值处理的最大值。
type:阈值类型。
dst:与输入源图像src具有相同大小、类型、通道数的图像。
功能:通常用于从灰度图中获取二进制图像或者用于去除图像噪声(即去除太大或太小的像素)。
findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> image, contours, hierarchy
参数含义:image:输入源图像,一个8位单通道图像,非零像素被视为1,零像素保持为0,即二进制图像。如果
mode等于RETR_CCOMP或RETR_FLOODFILL,则输入也可以是32位整数图像标签。
mode:轮廓检索模式。
method:轮廓逼近方法。
contours:检测到的轮廓,每个轮廓被存为点的矢量。
hierarchy:可选的输出矢量。包含图像的拓扑信息,具有和轮廓相同数量的元素。
offset:每个轮廓点的可选偏移量。
功能:从二进制图像中检索轮廓。轮廓是用于形状分析和物体检测识别的常用工具。
drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) -> image
参数含义:image:目标图片。
contours:所有输入轮廓,每个轮廓都被存储为点的矢量。
contourIdx:要绘制的轮廓的索引,如果为-1则绘制所有的轮廓。
color:轮廓绘制采用的颜色。
thickness:要绘制轮廓的线条的粗细,如果是负的,则绘制轮廓内线条。
lineType:线路连接。
hierarchy:需要绘制的轮廓的层次信息。仅当只需要绘制部分轮廓时这个参数才有用。
maxLevel:绘制轮廓的最大级别。如果为0,则绘制指定的轮廓;如果为1,则绘制所有轮廓(含嵌套
轮廓);如果是2,那么绘制所有轮廓,包括嵌套轮廓,嵌套的嵌套轮廓等等,但只有当有可用的层次
结构时参数才有效。
offset:可选的轮廓位移参数。
功能:绘制轮廓或填充轮廓。
好了,整个代码其实比较简单,主要是调用了上面几个函数。如果朋友们还有什么函数不清楚的可以自行查看文档。若对上述代码有疑问或建议的可以评论留言给我,以使我不断给大家提供更好的代码及博文。在此提前谢过,感谢朋友们的阅读!
最近开始接触图像处理,接到的首个任务就是将实验室用颜色标记好的数据再在原图上按不同颜色框出来,以在模型预测阶段检查预测效果。下面使用一张摇滚乐队Halestrom的图片进行说明。首先,我拿到的原图如下图所示:图1我们将原始图片按照人、地板、墙三种元素进行标记,得到下图:图2将上述两张图片输入我们的模型,那么模型能够做到给出一张新的图片它就能够输出一张按颜色分类标记元素的图片...
def show_img(path):
img = cv2.imread(path)
b, g, r = img[:, :, 0], img[:, :, 1], img[:, :, 2]
hist_b = cv2.calcHist([b], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([g
要使用
Python
和
OpenCV
实现
分水岭算法,你需要导入
OpenCV
库并使用其中的函数。下面是一个使用
OpenCV
实现
分水岭算法的简单示例代码:
```
python
import cv2
import numpy as np
# 读取图像
img = cv2.imread('image.jpg')
# 将图像转换为灰度
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 对灰度图像进行阈值处理
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 对阈值图像进行开运算,去除噪声
kernel = np.ones((3,3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 进行膨胀操作,使物体区域更加显著
sure_bg = cv2.dilate(opening, kernel, iterations=3)
#
标记
未知区域
sure_fg = cv2.erode(opening, kernel, iterations=3)
ret, markers = cv2.connectedComponents(sure_fg)
# 添加1以确保未知区域不会被
标记
为0
markers = markers + 1
markers[sure_bg == 255] = 0
# 使用分水岭算法进行图像分割
markers = cv2.watershed(img, markers)
img[markers == -1] = [0, 0, 255] # 将分割线
标记
为红色
# 显示结果图像
cv2.imshow('Segmented Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上面的代码中,首先读取图像并将其转换为灰度图像。然后使用阈值处理将图像转换为二值图像,并进行开运算去除噪声。接下来,进行膨胀和腐蚀操作,
标记
出背景和前景区域。然后使用connectedComponents函数对前景区域进行连通组件
标记
,添加1以确保未知区域不会被
标记
为0。最后,使用分水岭算法进行图像分割,并将分割线
标记
为红色。最终结果通过imshow函数显示出来。
请确保将代码中的'image.jpg'替换为你要进行分割的图像文件路径。你还可以根据需要对代码进行调整和优化。