2016-05-30 21:54:21 jsf921942722 阅读数 725

1.Dilate.h Dilate.c 为图像膨胀的头文件、核心函数
Dilate.h

#ifndef _DILATE_H_
#define _DILATE_H_

#ifdef __cplusplus
extern "C"
{
#endif
    /*
        *图像膨胀处理
    */
    int dilateFunction(float * inData, float * outData, int dataWidth, int dataHeight, int dilateWidth, int dilateHeight, int channels);

#ifdef __cplusplus
}
#endif
#endif

Dilate.c

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include "Dilate.h"
#include "myMath.h"



int dilateFunction(float * inData, float * outData, int dataWidth, int dataHeight, int dilateWidth, int dilateHeight, int channels){

    int widthTemp, heightTemp;
    int i, j;
    int m, n, z;
    float * dataTemp = NULL;
    int count = 0;
    float medianData = 0.f;
    if(channels > 32){
        printf("channels is larger.\n");
        return -1;
    }
    if(dilateWidth % 2 == 0){
        widthTemp = dilateWidth / 2 - 1;
    }else{
        widthTemp = dilateWidth / 2;
    }
    if(dilateHeight % 2 == 0){
        heightTemp = dilateHeight / 2 - 1;
    }else{
        heightTemp = dilateHeight / 2;
    }

    dataTemp = (float*)malloc(sizeof(float) * dilateWidth * dilateHeight);
    for(z = 0; z < channels; z ++){
        for(i = 0; i < dataHeight; i ++){
            for(j = 0; j < dataWidth; j ++){
                memset(dataTemp, 0, sizeof(float) * dilateWidth * dilateHeight);
                count = 0;
                medianData = 0.0f;
                for(m = -heightTemp; m < dilateHeight - heightTemp; m ++){
                    for(n = -widthTemp; n < dilateWidth - widthTemp; n ++){
                        if(i + m >= 0 && i + m < dataHeight && j + n >= 0 && j + n < dataWidth){
                            dataTemp[count] = inData[((i + m) * dataWidth + (j + n)) * channels + z];
                            count ++;
                        }
                    }
                }

                medianData = getMaxValue(dataTemp, count);
                outData[(i * dataWidth + j) * channels + z] = medianData;
            }
        }
    }
    free(dataTemp);
    return 0;
}

2.主程序

#include "stdafx.h"
#include "Tools.h"
#include "Dilate.h"
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
    int imageWidth, imageHeight;
    int channels = 1;
    Mat mImage = imread("D:\\workSpace\\VSWorkSpace\\ImageProcess\\ImageProcess\\dilateImage.jpg", 1);
    imshow("srcImage", mImage);
    float * imageData = NULL;
    float * imageOutData = NULL;
    imageWidth = mImage.cols;
    imageHeight = mImage.rows;
    channels = mImage.channels();
    imageData = (float*)malloc(sizeof(float) * imageWidth * imageHeight * channels);
    imageOutData = (float*)malloc(sizeof(float) * imageWidth * imageHeight * channels);
    uCharDataToFloatData(mImage.data, imageData, imageWidth, imageHeight, channels);
    dilateFunction(imageData, imageOutData, imageWidth, imageHeight, 3, 3, channels);
    floatDataToUCharData(imageOutData, mImage.data, imageWidth, imageHeight, channels, 1);
    imshow("dilate Image", mImage);
    waitKey(0);
    free(imageData);
    free(imageOutData);
    return 0;
}

getMaxValue();
该函数见链接
http://blog.csdn.net/jsf921942722/article/details/51527155
uCharDataToFloatData();
floatDataToUCharData();
这两个函数见链接
http://blog.csdn.net/jsf921942722/article/details/51526673
3.图像效果
*****************************3通道彩色图原图***********************
这里写图片描述
*****************************3通道彩色图膨胀处理后图***********************
这里写图片描述
*****************************1通道灰度图原图***********************
这里写图片描述
*****************************1通道灰度图膨胀处理后图***********************
这里写图片描述

2014-01-23 14:32:54 cxf7394373 阅读数 5492

腐蚀的算法:

用3x3的结构元素,扫描图像的每一个像素,用结构元素与其覆盖的二值图像做“与”操作:如果都为1,结果图像的该像素为1。否则为0。

结果:使二值图像减小一圈

B}Í S = { x,y | SxyÄ定义:E = B

 

膨胀的算法:

用3x3的结构元素,扫描图像的每一个像素,用结构元素与其覆盖的二值图像做“与”操作:如果都为0,结果图像的该像素为0。否则为1

结果:使二值图像扩大一圈

 S = { x,y | Sxy∩B ≠Ф}Å定义:E = B 

void erode_image(IplImage * src,IplImage * dst)
{	
	if(src == NULL || dst == NULL)
		return;
	
	int width = src->width;
	int height = src->height;

	//水平方向的腐蚀
	for (int i=0;i < src->height;i++)
	{
		for (int j=1;j < src->width - 1;j++)
		{
		//	data = ((uchar *)(src->imageData + src->widthStep * i))[j];
			if(((uchar *)(src->imageData + src->widthStep * i))[j] == 0)
			{
				((uchar *)(dst->imageData + dst->widthStep * i))[j] = 0;
				for (int k=0;k < 3;k++)
				{
				//	data = ((uchar *)(src->imageData + src->widthStep * i))[j + k -1];
					if(((uchar *)(src->imageData + src->widthStep * i))[j + k -1] == 255)
					{
						((uchar *)(dst->imageData + dst->widthStep * i))[j] = 255;
						break;
					}
				}
			}
			else
				((uchar *)(dst->imageData + dst->widthStep * i))[j] = 255;
		}
	}
	//垂直方向的腐蚀
	for (int i=0;i < dst->width;i++)
	{
		for (int j=1;j < dst->height - 1;j++)
		{
			//	data = ((uchar *)(src->imageData + src->widthStep * i))[j];
			if(((uchar *)(dst->imageData + dst->widthStep * j))[i] == 0)
			{
				((uchar *)(src->imageData + src->widthStep * j))[i] = 0;
				for (int k=0;k < 3;k++)
				{
					//	data = ((uchar *)(src->imageData + src->widthStep * i))[j + k -1];
					if(((uchar *)(dst->imageData + dst->widthStep * (j + k -1)))[i] == 255)
					{
						((uchar *)(src->imageData + src->widthStep * j))[i] = 255;
						break;
					}
				}
			}
			else
				((uchar *)(src->imageData + src->widthStep * j))[i] = 255;
		}
	}
}	
void dilate_image(IplImage * src,IplImage * dst)
{	
	if(src == NULL || dst == NULL)
		return;

	int width = src->width;
	int height = src->height;

	//水平方向的膨胀
	for (int i=0;i < src->height;i++)
	{
		for (int j=1;j < src->width - 1;j++)
		{
			if(((uchar *)(src->imageData + src->widthStep * i))[j] == 255)
			{
				((uchar *)(dst->imageData + dst->widthStep * i))[j] = 255;
				for (int k=0;k < 3;k++)
				{
					if(((uchar *)(src->imageData + src->widthStep * i))[j + k -1] == 0)
					{
						((uchar *)(dst->imageData + dst->widthStep * i))[j] = 0;
						break;
					}
				}
			}
			else
				((uchar *)(dst->imageData + dst->widthStep * i))[j] = 0;
		}
	}
	//垂直方向的膨胀
	for (int i=0;i < dst->width;i++)
	{
		for (int j=1;j < dst->height - 1;j++)
		{
			//	data = ((uchar *)(src->imageData + src->widthStep * i))[j];
			if(((uchar *)(dst->imageData + dst->widthStep * j))[i] == 255)
			{
				((uchar *)(src->imageData + src->widthStep * j))[i] = 255;
				for (int k=0;k < 3;k++)
				{
					//	data = ((uchar *)(src->imageData + src->widthStep * i))[j + k -1];
					if(((uchar *)(dst->imageData + dst->widthStep * (j + k -1)))[i] == 0)
					{
						((uchar *)(src->imageData + src->widthStep * j))[i] = 0;
						break;
					}
				}
			}
			else
				((uchar *)(src->imageData + src->widthStep * j))[i] = 0;
		}
	}
}
image = cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE);
		dst1 = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels);
		
		dilate_image(image,dst1);
		erode_image(image,dst1);

		cvSaveImage(str,image);

原图


结果



2019-01-09 20:22:10 qq_42887760 阅读数 753

形态学操作(morphology operators)-膨胀与腐蚀(Dilation与Erosion)。

  • 图像形态学操作
    • 图像形态学操作 – 基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学
    • 形态学有四个基本操作:腐蚀、膨胀、开、闭
    • 膨胀与腐蚀是图像处理中最常用的形态学操作手段
    • 腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。
  • 膨胀与腐蚀能实现多种多样的功能,主要如下:
    • 消除噪声
    • 分割(isolate)出独立的图像元素,在图像中连接(join)相邻的元素。
    • 寻找图像中的明显的极大值区域或极小值区域
    • 求出图像的梯度
相关的 API

getStructuringElement(int shape, Size ksize, Point anchor)

  • 形状 (MORPH_RECT \MORPH_CROSS \MORPH_ELLIPSE)
  • 大小
  • 锚点 默认是Point(-1, -1)意思就是中心像素

1. 形态学操作-膨胀

  • 相关的API:dilate(src, dst, kernel);
    在这里插入图片描述
  • 跟卷积操作类似,假设有图像A和结构元素B,结构元素B在A上面移动,其中B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状
  • 形态学操作-膨胀(感官上图像变细,变白了)
    在这里插入图片描述

2. 形态学操作-腐蚀

  • 相关的API:erode(src, dst, kernel)
    在这里插入图片描述
  • 腐蚀跟膨胀操作的过程类似,唯一不同的是以最小值替换锚点重叠下图像的像素值
  • 形态学操作-腐蚀(感官上图像变粗,变黑了)

在这里插入图片描述

动态调整结构元素大小

  • TrackBar –
    createTrackbar(const String & trackbarname, const String winName, int* value, int count, Trackbarcallback func, void* userdata=0)
    其中最中要的是 callback 函数功能。如果设置为NULL就是说只有值update,但是不会调用callback的函数。

代码示例

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace cv;
using namespace std;

Mat src,erode_dst,dilate_dst;
char input_Win[]="input windows",dilate_Win[]="Dilation windows",Erode_Win[]="Erosion windows";
int dilate_elem=0,erode_elem=0;
int dilate_size=0,erode_size=0;
int const max_elem=2;
int const max_kernel_size=21;

void Dilation(int,void*);//膨胀
void Erosion(int,void*);//腐蚀

int main(int argc,char** argv){
	//1、加载图像,可以是BGR或灰度
	src = imread("E:/Experiment/OpenCV/Pictures/lenanoise.jpg");
	if(src.empty()){
		printf("Could not load Image ...");
		return -1;
	}

	namedWindow(input_Win,CV_WINDOW_AUTOSIZE);
	imshow(input_Win,src);
	
	//2、创建两个窗口(一个用于膨胀Dilation,另一个用于侵蚀Erosion)
	//每次移动任何滑块时,都会调用用户的Erosion或Dilation函数,它将根据当前的trackbar值更新输出图像。
	namedWindow(dilate_Win,CV_WINDOW_AUTOSIZE);
	namedWindow(Erode_Win,CV_WINDOW_AUTOSIZE);
	
	//3、为每个操作创建两组轨道栏:
	
	//3.1、第一个轨道栏“Element”返回erosion_elem或dilation_elem
	createTrackbar("卷积核类型",dilate_Win,&dilate_elem,max_elem,Dilation);
	//3.2、第二个轨道栏“内核大小”返回相应操作的erosion_size或dilation_size。
	createTrackbar("卷积核大小",dilate_Win,&dilate_size,max_kernel_size,Dilation);
	
	
	createTrackbar("卷积核类型",Erode_Win,&erode_elem,max_elem,Erosion);
	createTrackbar("卷积核大小",Erode_Win,&erode_size,max_kernel_size,Erosion);

	Dilation( 0, 0 );
	Erosion( 0, 0 );

	waitKey(0);
}

//膨胀
void Dilation(int,void*){
	int dilate_type;//内核选择三种形状中的任何一种
	if(dilate_elem == 0){ dilate_type = MORPH_RECT; }//矩形内核:MORPH_RECT
	else if(dilate_elem == 1){ dilate_type = MORPH_CROSS; }//十字架内核:MORPH_CROSS
	else if(dilate_elem == 2){ dilate_type = MORPH_ELLIPSE; }//椭圆内核:MORPH_ELLIPSE

	Mat kernel = getStructuringElement(dilate_type,Size(2*dilate_size+1,2*dilate_size+1),Point(dilate_size,dilate_size));
	dilate(src,dilate_dst,kernel);
	imshow( dilate_Win, dilate_dst );
}

//腐蚀
void Erosion(int,void*){
	int erosion_type;//内核选择三种形状中的任何一种
	if(erode_elem == 0){ erosion_type = MORPH_RECT; }//矩形内核:MORPH_RECT
	else if(erode_elem == 1){ erosion_type = MORPH_CROSS; }//十字架内核:MORPH_CROSS
	else if(erode_elem == 2){ erosion_type = MORPH_ELLIPSE; }//椭圆内核:MORPH_ELLIPSE

	Mat kernel = getStructuringElement(erosion_type,Size(2*erode_size+1,2*erode_size+1),Point(erode_size,erode_size));
	erode(src,erode_dst,kernel);
	imshow( Erode_Win, erode_dst );
}

在这里插入图片描述

推荐参考:

  1. https://blog.csdn.net/LYKymy/article/details/83153122
  2. https://blog.csdn.net/huanghuangjin/article/details/80945770
2017-05-27 22:40:07 yi_tech_blog 阅读数 2269

应用背景:在一些情况下,我们需要“增长”或者“粗化”二值图像中的物体,初等形态学运算中的膨胀操作能实现这种目的。

基本原理:在形态学中,膨胀操作是腐蚀操作的逆运算,因此可以通过对原图像的补集进行腐蚀来得到膨胀后的图像。图像A被结构元B膨胀用集合论来表示如下式:

                                                                                           

其中,Ac为A的补集。上式表示结构元对图像A进行膨胀的结果集合是先将B相对原点旋转180度得到-B,然后使用-B对Ac进行腐蚀,最后求补集。还可用D(A,B)表示膨胀。


膨胀操作的C++实现:

void Morphology::ImgDilation(unsigned char *imgBufIn,unsigned char *imgBufOut,int imgWidth,int imgHeight,
					 int *TempBuf, int TempW, int TempH)
{
	int lineByte=(imgWidth+3)/4*4;
	int i,j,k,l;
	for(i=0;i<imgHeight;i++)
	{
		for(j=0;j<imgWidth;j++)
		{
			*(imgBufIn+i*lineByte+j)=255-*(imgBufIn+i*lineByte+j);
		}
	}
	int *tempMask=new int[TempW*TempH];
	for(k=0;k<TempH;k++)
	{
		for(l=0;l<TempW;l++)
		{
			tempMask[k*TempW+l]=TempBuf[(TempH-1-k)*TempW+TempW-1-l];
		}
	}
	int flag;	
	for(i=TempH/2;i<imgHeight-TempH/2;i++)
	{
		for(j=TempW/2;j<imgWidth-TempW/2;j++)
		{					
			flag=1;
			for(k=-TempH/2;k<=TempH/2;k++)
			{
				for(l=-TempW/2;l<=TempW/2;l++)
				{				
					if(tempMask[(k+TempH/2)*TempW+l+TempW/2])
					{
						if(!*(imgBufIn+(i+k)*lineByte+j+l))
							flag=0;	
					}
				}
			}
			if(flag)
				*(imgBufOut+i*lineByte+j)=255;
			else
				*(imgBufOut+i*lineByte+j)=0;
		}
	}
	for(i=0;i<imgHeight;i++)
	{
		for(j=0;j<imgWidth;j++)
		{
			*(imgBufOut+i*lineByte+j)=255-*(imgBufOut+i*lineByte+j);
		}
	}	
	for(i=0;i<imgHeight;i++
	{
		for(j=0;j<imgWidth;j++)
		{
			*(imgBufIn+i*lineByte+j)=255-*(imgBufIn+i*lineByte+j);
		}
	}	
	delete []tempMask;
}



运行结果:在VS中运行MFC多文档程序,结果如下

膨胀前的lena图像


膨胀后的lena图像


从膨胀处理结果来看,图像前景区域(白色部分)增大,边界变得模糊。

2016-11-08 23:21:34 attilax 阅读数 1168

Atitit 图像处理—图像形态学(膨胀与腐蚀)

 

1.1. 膨胀与腐蚀1

1.2. 图像处理之二值膨胀及应用2

1.3. 测试原理,可以给一个5*5pic,测试膨胀算法5

1.4. Photoshop里面的处理5

1.5. 类库的处理,好像没找到jhlabs,6

1.6. Attilax 源码6

 

1.1. 膨胀与腐蚀

  说概念可能很难解释,我们来看图,首先是原图:

  膨胀以后会变成这样:

  腐蚀以后则会变成这样:

  看起来可能有些莫名其妙,明明是膨胀,为什么字反而变细了,而明明是腐蚀,为什么字反而变粗了。

实际上,所谓膨胀应该指

  较亮色块膨胀。

而所谓腐蚀应该指

较亮色块腐蚀。

 

1.2. 图像处理之二值膨胀及应用

基本原理:

膨胀是图像形态学的两个基本操作之一,另外一个是腐蚀操作。最典型的应用是在二值图像

中使用这两个基本操作,是很多识别技术中重要的中间处理步骤。在灰度图像中根据阈值同

样可以完成膨胀与腐蚀操作。对一幅二值图像f(x,y)完成膨胀操作,与对图像的卷积操作类

似,要有个操作数矩阵,最常见的为3X3的矩阵,与卷积操作不同的,是如果矩阵中的像素

点有任意一个点的值是前景色,则设置中心像素点为前景色,否则不变。

 

形态学运算中腐蚀,膨胀,开运算和闭运算:
1. 腐蚀是一种消除边界点,使边界向内部收缩的过程。

可以用来消除小且无意义的物体。
腐蚀的算法:
3x3的结构元素,扫描图像的每一个像素
用结构元素与其覆盖的二值图像做操作
如果都为1,结果图像的该像素为1。否则为0
结果:使二值图像减小一圈

2. 膨胀是将与物体接触的所有背景点合并到该物体中,使边界向外部扩张的过程。

可以用来填补物体中的空洞。
膨胀的算法:
3x3的结构元素,扫描图像的每一个像素
用结构元素与其覆盖的二值图像做操作
如果都为0,结果图像的该像素为0。否则为1
结果:使二值图像扩大一圈

3. 先腐蚀后膨胀的过程称为开运算。

用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。

4. 先膨胀后腐蚀的过程称为闭运算。

用来填充物体内细小空洞、连接邻近物体、平滑其边界的同时并不明显改变其面积。

 

 

让我们来看看实际上是怎样进行膨胀运算的。在图6.14中,左边是被处理的图象X(二值图象,我们针对的是黑点),中间是结构元素B。膨胀的方法是,拿B的中心点和X上的点及X周围的点一个一个地对,如果B上有一个点落在X的范围内,则该点就为黑;右边是膨胀后的结果。可以看出,它包括X的所有范围,就象X膨胀了一圈似的。

6.13   膨胀的示意图

6.14   膨胀运算

6.15为图6.11膨胀后的结果图,能够很明显的看出膨胀的效果。

 

 

粉红色的方格每次在X/Y前进一个像素方格,就会产生一个新的输出像素,图中深蓝色的代

表要输出的像素方格,走完全部的像素方格,就得到了所有输出像素。

 

图中,粉红色的矩阵表示卷积操作数矩阵,黑色表示源图像每个方格代表一个像素点。

 

 

 

1.3. 测试原理,可以给一个5*5pic,测试膨胀算法

 */

public class ImgGene4test {

public static void main(String[] args) {

BufferedImage dest = new BufferedImage(5,5 ,1);

imgx.setBackgroudColor_White(dest);

dest.setRGB(2, 2, new Color(0,0,0).getRGB());

imgx.save_overwrite(dest, "C:\\00capch\\p5.jpg");

System.out.println("==f");

 

}

1.4. Photoshop里面的处理

键后有个文字加粗的.不过我想这个应该满足不了你的要求.你可以先把文字栅格化,然后选择->修改->扩展选区,再进行填充.直到你想要的效果.建议你先把文字做得比你想要的大一点.再进行此操作,得到你想要效果后再缩小.因为是把选区进行扩展再填充,所以边边色起据齿,放大做再缩小这个问题就不会严重了.加分加分.

 

选中文字,在“字符”窗口的左下角,点第一个“T”按钮,即可变粗,如果还不够,那就按住ctrl+鼠标单击文字图层=》“选择”=》修改=》扩展,输入扩展数字确定=》新建图层,填充即可

 

1.5. 类库的处理,好像没找到jhlabs,

1.6. Attilax 源码

 

@Override

public BufferedImage filter(BufferedImage src, BufferedImage dest) {

BufferedImage dest2 = imgx.new_BackgroudColor_White(src.getWidth(), src.getHeight());

Matrix mtrx = new Matrix(3, 3).setImg(src);

imgx.trave(src, (x, y) -> {

System.out.println("" + x + ":" + y);

 

mtrx.fill_and_setMtrx_leftTop_XY(x, y);

 

boolean mtrx_hasAnyForgeColor = mtrx.hasAnyForgeColor(mtrx_item_color -> {

// dark,,so is forge color.. bkgrd lit..

return (imgx.isDarkColor(imgx.gray(mtrx_item_color)));

 

});

if (mtrx_hasAnyForgeColor) {

int forgeColor2 = mtrx.getForgeColor();

mtrxCenterXy_inImg = mtrx.getCenterXy();

try {

dest2.setRGB((int) mtrxCenterXy_inImg.get("x"), (int) mtrxCenterXy_inImg.get("y"), forgeColor2);

} catch (ArrayIndexOutOfBoundsException e) {

System.out.println("ArrayIndexOutOfBoundsException  x:" + x + ",y:" + y);

}

 

}

});

 

return dest2;

}

 

 

图像处理之二值膨胀及应用 - 流浪的鱼 - 博客频道 - CSDN.NET.html

图像处理之二值腐蚀 - 流浪的鱼 - 博客频道 - CSDN.NET.html

图像的膨胀与腐蚀、细化 - 公爵女子 - 博客园.html

java,不依赖于第三方jar的图片处理类 - dragonsoar - ITeye技术网站.html

 

作者:: 绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿尔 拉帕努伊 ) 

汉字名:艾提拉(艾龙)   EMAIL:1466519819@qq.com

转载请注明来源: http://blog.csdn.net/attilax

Atiend

 

没有更多推荐了,返回首页