使用OpenCV获取图片连通域数量,并用不同颜色标记函

一,原图和效果图

二,代码

//#########################产生随机颜色#########################
cv::Scalar icvprGetRandomColor()
{
	uchar r = 255 * (rand() / (1.0 + RAND_MAX));
	uchar g = 255 * (rand() / (1.0 + RAND_MAX));
	uchar b = 255 * (rand() / (1.0 + RAND_MAX));
	return cv::Scalar(b, g, r);
}
//#########################产生随机颜色#########################

//########################种子填充法)#########################
void ConnectedCountBySeedFill(const cv::Mat& _binImg, cv::Mat& _lableImg, int &iConnectedAreaCount)
{
  //拓宽1个像素的原因是:如果连通域在边缘,运行此函数会异常崩溃,所以需要在周围加一圈0值,确保连通域不在边上
	//==========图像周围拓宽1个像素============================================
	int top, bottom;      //【添加边界后的图像尺寸】
	int leftImage, rightImage;
	int borderType = BORDER_CONSTANT; //BORDER_REPLICATE
	//【初始化参数】
	top = (int)(1); bottom = (int)(1);
	leftImage = (int)(1); rightImage = (int)(1);
	Mat _binImg2, _binImg3;
	_binImg.copyTo(_binImg2);
		//初始化参数value
		Scalar value(0); //填充值
		//创建图像边界
		copyMakeBorder(_binImg2, _binImg3, top, bottom, leftImage, rightImage, borderType, value);

	//==========图像周围拓宽1个像素============================================

	// connected component analysis (4-component)
	// use seed filling algorithm
	// 1. begin with a foreground pixel and push its foreground neighbors into a stack;
	// 2. pop the top pixel on the stack and label it with the same label until the stack is empty
	//
	// foreground pixel: _binImg(x,y) = 1
	// background pixel: _binImg(x,y) = 0 

	if (_binImg3.empty() ||
		_binImg3.type() != CV_8UC1)
	{
		return;
	}

	_lableImg.release();
	_binImg3.convertTo(_lableImg, CV_32SC1);
	int icount = 0;
	int label = 1; // start by 2 

	int rows = _binImg3.rows - 1;
	int cols = _binImg3.cols - 1;
	for (int i = 1; i < rows - 1; i++)
	{
		int* data = _lableImg.ptr<int>(i);  //取一行数据
		for (int j = 1; j < cols - 1; j++)
		{
			if (data[j] == 1)  //像素不为0
			{
				std::stack<std::pair<int, int>> neighborPixels;   //新建一个栈
				neighborPixels.push(std::pair<int, int>(i, j));   // 像素坐标: <i,j> ,以该像素为起点,寻找连通域
				++label; // 开始一个新标签,各连通域区别的标志
				while (!neighborPixels.empty())
				{
					// 获取堆栈中的顶部像素并使用相同的标签对其进行标记
					std::pair<int, int> curPixel = neighborPixels.top();
					int curX = curPixel.first;
					int curY = curPixel.second;
					_lableImg.at<int>(curX, curY) = label; //对图像对应位置的点进行标记

					// 弹出顶部像素  (顶部像素出栈)
					neighborPixels.pop();

						// 加入8邻域点
						if (_lableImg.at<int>(curX, curY - 1) == 1)
						{// 左点
							neighborPixels.push(std::pair<int, int>(curX, curY - 1)); //左边点入栈
						}

						if (_lableImg.at<int>(curX, curY + 1) == 1)
						{// 右点
							neighborPixels.push(std::pair<int, int>(curX, curY + 1)); //右边点入栈
						}

						if (_lableImg.at<int>(curX - 1, curY) == 1)
						{// 上点
							neighborPixels.push(std::pair<int, int>(curX - 1, curY)); //上边点入栈
						}

						if (_lableImg.at<int>(curX + 1, curY) == 1)
						{// 下点
							neighborPixels.push(std::pair<int, int>(curX + 1, curY)); //下边点入栈
						}
						//===============补充到8连通域======================================================
						if (_lableImg.at<int>(curX - 1, curY - 1) == 1)
						{// 左上点
							neighborPixels.push(std::pair<int, int>(curX - 1, curY - 1)); //左上点入栈
						}

						if (_lableImg.at<int>(curX - 1, curY + 1) == 1)
						{// 右上点
							neighborPixels.push(std::pair<int, int>(curX - 1, curY + 1)); //右上点入栈
						}

						if (_lableImg.at<int>(curX + 1, curY - 1) == 1)
						{// 左下点
							neighborPixels.push(std::pair<int, int>(curX + 1, curY - 1)); //左下点入栈
						}

						if (_lableImg.at<int>(curX + 1, curY + 1) == 1)
						{// 右下点
							neighborPixels.push(std::pair<int, int>(curX + 1, curY + 1)); //右下点入栈
						}
					//===============补充到8连通域======================================================
				}
			}
		}
	}
	iConnectedAreaCount = label - 1; //因为label从2开始计数的
	int a = 0;
}
###########################################################
//#############添加颜色#####################################
Mat PaintColor(Mat src, int iConnectedAreaCount)
{
	int rows = src.rows;
	int cols = src.cols;

	//cv::Scalar(b, g, r);
	std::map<int, cv::Scalar> colors;
	for (int n = 1; n <= iConnectedAreaCount + 1; n++)
	{
		colors[n] = icvprGetRandomColor(); //根据不同标志位产生随机颜色

		cv::Scalar color = colors[n];
		int a = color[0];
		int b = color[1];
		int c = color[2];
		int d = 0;
	}

	Mat dst2(rows, cols, CV_8UC3);
	dst2 = cv::Scalar::all(0);
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			int value = src.at<int>(i, j);
			if (value>1)
			{
				cv::Scalar color = colors[value];
				int a = color[0];
				int b = color[1];
				int c = color[2];
				dst2.at<Vec3b>(i, j)[0] = color[0];
				dst2.at<Vec3b>(i, j)[1] = color[1];
				dst2.at<Vec3b>(i, j)[2] = color[2];
			}
		}
	}
	return dst2;
}
//#############添加颜色##################################

//########调用##########################################
  Mat binImage = cv::imread("D:\\sxl\\处理图片\\testImages\\22.jpg", 0);
	threshold(binImage, binImage, 50, 1, CV_THRESH_BINARY_INV);

	// 连通域标记
	Mat labelImg;
	int iConnectedAreaCount = 0; //连通域个数
	ConnectedCountBySeedFill(binImage, labelImg, iConnectedAreaCount);//针对黑底白字
	int a=iConnectedAreaCount;

	// 显示结果
	Mat dstColor2=PaintColor(labelImg,iConnectedAreaCount);
	imshow("colorImg", dstColor2);

	Mat grayImg;
	labelImg *= 10;
	labelImg.convertTo(grayImg, CV_8UC1);
	imshow("labelImg", grayImg);

	waitKey(0);
//########调用##########################################

补充知识:Opencv快速获取连通域

对于ndarray数据中的连通域查找,opencv提供了接口,非常方便。

import cv2
import numpy as np

img = np.array([
  [0, 255, 255, 0, 0, 0, 255, 255,],
  [0, 0, 255, 0, 255, 255, 255, 0],
  [0, 0, 0, 0, 255, 255, 0, 255],
  [255, 255, 0, 0, 0, 0, 0, 0],
  [255, 255, 0, 0, 0, 0, 0, 0],
  [255, 255, 0, 0, 0, 0, 0, 0]
], dtype=np.uint8)

num, labels = cv2.connectedComponents(img)
labels_dict = {i:[] for i in range(1, num+1)}
height, width = img.shape
for h in range(height):
  for w in range(width):
    if labels[h][w] in labels_dict:
      labels_dict[labels[h][w]].append([h,w])

cv2.connectedComponents()函数返回查找到的连通域个数和对应的label。

上面代码返回连通域个数为4(包含值为0区域,可通过lables过滤), labels结果如图所示:

以上这篇使用OpenCV获取图片连通域数量,并用不同颜色标记函就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • OpenCV-Python实现轮廓检测实例分析

    相比C++而言,Python适合做原型.本系列的文章介绍如何在Python中用OpenCV图形库,以及与C++调用相应OpenCV函数的不同之处.这篇文章介绍在Python中使用OpenCV检测并绘制轮廓. 提示: 转载请详细注明原作者及出处,谢谢! 本文介绍在OpenCV-Python中检测并绘制轮廓的方法. 本文不介详细的理论知识,读者可从其他资料中获取相应的背景知识.笔者推荐清华大学出版社的<图像处理与计算机视觉算法及应用(第2版)>. 轮廓检测 轮廓检测也是图像处理中经常用到的.Ope

  • python验证码识别教程之利用投影法、连通域法分割图片

    前言 今天这篇文章主要记录一下如何切分验证码,用到的主要库就是Pillow和Linux下的图像处理工具GIMP.首先假设一个固定位置和宽度.无粘连.无干扰的例子学习一下如何使用Pillow来切割图片. 使用GIMP打开图片后,按 加号 放大图片,然后点击View->Show Grid来显示网格线: 其中,每个正方形边长为10像素,所以数字1切割坐标为左20.上20.右40.下70.以此类推可以知道剩下3个数字的切割位置. 代码如下: from PIL import Image p = Image

  • Python Opencv实现图像轮廓识别功能

    本文实例为大家分享了python opencv识别图像轮廓的具体代码,供大家参考,具体内容如下 要求:用矩形或者圆形框住图片中的云朵(不要求全部框出) 轮廓检测 Opencv-Python接口中使用cv2.findContours()函数来查找检测物体的轮廓. import cv2 img = cv2.imread('cloud.jpg') # 灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.th

  • 使用OpenCV获取图片连通域数量,并用不同颜色标记函

    一,原图和效果图 二,代码 //#########################产生随机颜色######################### cv::Scalar icvprGetRandomColor() { uchar r = 255 * (rand() / (1.0 + RAND_MAX)); uchar g = 255 * (rand() / (1.0 + RAND_MAX)); uchar b = 255 * (rand() / (1.0 + RAND_MAX)); return

  • OpenCV获取视频的每一帧并保存为.jpg图片

    本文实例为大家分享了OpenCV获取视频的每一帧并保存为图片的具体代码,供大家参考,具体内容如下 #include<opencv2\opencv.hpp> #include <iostream> #include <stdio.h> #include<fstream> using namespace std; using namespace cv; //获取视频中的人脸 int main() { //打开视频文件:其实就是建立一个VideoCapture结构

  • OpenCV连通域数量统计学习示例

    目录 学习目标: 核心代码 代码执行说明 学习目标: 1.输入图像为分割结果图像 2.根据种子填充法思路,遍历图像,得到每个连通域外接矩形坐标信息.面积信息 核心代码 /* Input: src: 待检测连通域的二值化图像 Output: dst: 标记后的图像 featherList: 连通域特征的清单(可自行查阅文档) return: 连通域数量. */ int connectionDetect(Mat &src, Mat &dst, vector<Feather> &am

  • Python+OpenCV实现图片及视频中选定区域颜色识别

    近期,需要实现检测摄像头中指定坐标区域内的主体颜色,通过查阅大量相关的内容,最终实现代码及效果如下,具体的实现步骤在代码中都详细注释,代码还可以进一步优化,但提升有限. 主要实现过程:按不同颜色的取值范围,对图像进行循环遍历,转换为灰度图,将本次遍历的颜色像素转换为白色,对白色部分进行膨胀处理,使其更加连续,计算白色部分外轮廓包围的面积累加求和,比较每种颜色围起来面积,保存最大值及其颜色,所有颜色遍历完后,返回最大值对应的颜色,显示在图像上 如果有类似的颜色识别的任务,可参考以下代码修改后实现具

  • python获取图片颜色信息的方法

    本文实例讲述了python获取图片颜色信息的方法.分享给大家供大家参考.具体分析如下: python的pil模块可以从图片获得图片每个像素点的颜色信息,下面的代码演示了如何获取图片所有点的颜色信息和每种颜色的数量. from PIL import Image image = Image.open("jb51.gif") image.getcolors() 返回结果如下 复制代码 代码如下: ..., (44, (72, 64, 55, 255)), (32, (231, 208, 14

  • java中ImageReader和BufferedImage获取图片尺寸实例

    ImageReader 对象通常由特定格式的服务提供者接口 (SPI) 类实例化.服务提供者类(例如 ImageReaderSpi 的实例)向 IIORegistry 注册,后者使用前者进行格式识别和表示可用格式 reader 和 writer. BufferedImage子类描述具有可访问图像数据缓冲区的Image.BufferedImage由图像数据的ColorModel和Raster组成.Raster的SampleModel中band的数量和类型必须与ColorModel所要求的数量和类型

  • python 获取图片分辨率的方法

    pil版: from PIL import Image filename = r'E:\data\yangben\0.jpg' img = Image.open(filename) imgSize = img.size #图片的长和宽 print (imgSize) maxSize = max(imgSize) #图片的长边 minSize = min(imgSize) #图片的短边 print(maxSize, minSize) opencv版: img = cv2.imread(F1) sp

  • python opencv将图片转为灰度图的方法示例

    使用opencv将图片转为灰度图主要有两种方法,第一种是将彩色图转为灰度图,第二种是在使用OpenCV读取图片的时候直接读取为灰度图. 将彩色图转为灰度图 import cv2 import numpy as np if __name__ == "__main__": img_path = "timg.jpg" img = cv2.imread(img_path) #获取图片的宽和高 width,height = img.shape[:2][::-1] #将图片缩小

  • python openCV获取人脸部分并存储功能

    本文实例为大家分享了python openCV获取人脸部分并存储的具体代码,供大家参考,具体内容如下 #-*- coding:utf-8 -*- import cv2 import os import time import base64 import numpy as np save_path = 'E:\\opencv\\2018-04-24OpenCv\\RAR\\savetest' faceCascade = cv2.CascadeClassifier( './haarcascade_f

  • Python+OpenCV 实现图片无损旋转90°且无黑边

    0. 引言 有如上一张图片,在以往的图像旋转处理中,往往得到如图所示的图片. 然而,在进行一些其他图像处理或者图像展示时,黑边带来了一些不便.本文解决图片旋转后出现黑边的问题,实现了图片尺寸不变的旋转(以上提到的黑边是图片的一部分). 1. 方法流程 (1)旋转图片,得到有黑边的旋转图片. (2)找出图片区域(不含黑边)的位置. (3)创建一个空图片(其实是矩阵). (4)将图片区域搬到此空图片. 2. 程序 #!/usr/bin/python # -*- coding: UTF-8 -*- "

随机推荐