2018-06-10 21:39:16 linxid 阅读数 1553
  • 1.14.ARM裸机第十四部分-LCD显示器

    本期课程主要讲解LCD。首先讲了LCD显示原理、颜色原理、LCD显示器的主要性能参数、概念等,然后进入了LCD编程实战部分,用6节课从零开始带大家编写程序在LCD上显示像素、背景、线条、文字、图片等内容。本课程的学习目标是掌握LCD显示相关的概念和编程方法,对显存的作用和填充有本质的了解,对图像显示有一定的认识。

    8381 人正在学习 去看看 朱有鹏

图像作为一个像素矩阵,TensorFlow提供了多个函数用于图像处理。TensorFlow的图像处理部分和OpenCV不同,主要服务于深度学习。比如图像的旋转不变性等等。在功能上肯定不如OpenCV丰富。

1、图像编码处理

虽然图片就是一个三维矩阵,但是所有的图片存储时都会被压缩,也就是编码和解码的过程。所以我们从一张图像得到三维矩阵,首先需要解码。

import matplotlib.pyplot as plt
import tensorflow as tf   
import numpy as np

# 对图片进行解码,并且修改其大小,将其打印出来(矩阵值)
image_raw_data = tf.gfile.FastGFile('datasets/cat.jpg','rb').read()
with tf.Session() as sess1:
    img_data = tf.image.decode_jpeg(image_raw_data)
    print(img_data.eval())
    img_data.set_shape([1797, 2673, 3])
    print(img_data.get_shape())

# 利用matplotlib,打印图片
with tf.Session() as sess2:
    plt.imshow(img_data.eval())
    print(img_data.get_shape())
    plt.show()

image.png

2、图像大小调整

对图像的大小进行调整,TensorFlow提供了多种方法,现总结如下。

2.1 放大 缩小

# 对图片进行放大缩小处理,原图信息不变,但是尺寸发生变化
with tf.Session() as sess3:
    # 首先将图像的像素值从0-255,变成浮点数 0-1
    image_float = tf.image.convert_image_dtype(img_data, tf.float32)
    resized = tf.image.resize_images(image_float, [300,300], method=0)

    plt.imshow(resized.eval())
    plt.show()

image.png

调整大小算法(method):
  • method = 0:双线性插值;
  • method = 1:最近邻插值;
  • method = 2:双三次插值;
  • method = 3:面积插值法;

2.2 裁剪 填充

对其进行裁剪或者填充.但是原图像的大小并没有变.

with tf.Session() as sess:    
    croped = tf.image.resize_image_with_crop_or_pad(img_data, 1000, 1000)
    padded = tf.image.resize_image_with_crop_or_pad(img_data, 3000, 3000)
    plt.imshow(croped.eval())
    plt.show()
    plt.imshow(padded.eval())
    plt.show()

image.png
image.png

2.3 按比例调整大小

截取中间50%的图片

with tf.Session() as sess:   
    central_cropped = tf.image.central_crop(img_data, 0.5)
    plt.imshow(central_cropped.eval())
    plt.show()

image.png

3、图像翻转

对图像进行上下,左右的翻转。

with  tf.Session() as sess: 
    # 上下翻转
    #flipped1 = tf.image.flip_up_down(img_data)
    # 左右翻转
    #flipped2 = tf.image.flip_left_right(img_data)

    #对角线翻转
    transposed = tf.image.transpose_image(img_data)
    plt.imshow(transposed.eval())
    plt.show()

    # 以一定概率上下翻转图片。
    #flipped = tf.image.random_flip_up_down(img_data)
    # 以一定概率左右翻转图片。
    #flipped = tf.image.random_flip_left_right(img_data)

image.png

4、对图像进行色彩调整


with  tf.Session() as sess:
    # 在进行一系列图片调整前,先将图片转换为实数形式,有利于保持计算精度。
    image_float = tf.image.convert_image_dtype(img_data, tf.float32)

    # 将图片的亮度-0.5。
    #adjusted = tf.image.adjust_brightness(image_float, -0.5)

    # 将图片的亮度-0.5
    #adjusted = tf.image.adjust_brightness(image_float, 0.5)

    # 在[-max_delta, max_delta)的范围随机调整图片的亮度。
    adjusted = tf.image.random_brightness(image_float, max_delta=0.5)

    # 将图片的对比度-5
    #adjusted = tf.image.adjust_contrast(image_float, -5)

    # 将图片的对比度+5
    #adjusted = tf.image.adjust_contrast(image_float, 5)

    # 在[lower, upper]的范围随机调整图的对比度。
    #adjusted = tf.image.random_contrast(image_float, lower, upper)

    # 在最终输出前,将实数取值截取到0-1范围内。
    adjusted = tf.clip_by_value(adjusted, 0.0, 1.0)
    plt.imshow(adjusted.eval())
    plt.show()

image.png

5、调整图像色相和饱和度

with tf.Session() as sess:
    # 在进行一系列图片调整前,先将图片转换为实数形式,有利于保持计算精度。
    image_float = tf.image.convert_image_dtype(img_data, tf.float32)

    adjusted = tf.image.adjust_hue(image_float, 0.1)
    #adjusted = tf.image.adjust_hue(image_float, 0.3)
    #adjusted = tf.image.adjust_hue(image_float, 0.6)
    #adjusted = tf.image.adjust_hue(image_float, 0.9)

    # 在[-max_delta, max_delta]的范围随机调整图片的色相。max_delta的取值在[0, 0.5]之间。
    #adjusted = tf.image.random_hue(image_float, max_delta)

    # 将图片的饱和度-5。
    #adjusted = tf.image.adjust_saturation(image_float, -5)
    # 将图片的饱和度+5。
    #adjusted = tf.image.adjust_saturation(image_float, 5)
    # 在[lower, upper]的范围随机调整图的饱和度。
    #adjusted = tf.image.random_saturation(image_float, lower, upper)

    # 将代表一张图片的三维矩阵中的数字均值变为0,方差变为1。
    #adjusted = tf.image.per_image_whitening(image_float)

    # 在最终输出前,将实数取值截取到0-1范围内。
    adjusted = tf.clip_by_value(adjusted, 0.0, 1.0)
    plt.imshow(adjusted.eval())
    plt.show()

image.png

6、对图片增加标注框

# 在图片中添加标注框,和裁剪
with tf.Session() as sess8:
    # 生成标准框
    # 设置标注框的位置
    boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7], [0.35, 0.47, 0.5, 0.56]]])

    # 图片太大,标注框无法显示,所以将图片变小
    image_small = tf.image.resize_images(image_float, [180, 267], method=0)
    # 对数据进行扩充,将其变为4维矩阵
    batchced_img = tf.expand_dims(image_small, 0)
    # draw_bounding_boxes处理多张图片,所以是一个四维矩阵,需要对原图像进行扩充
    image_with_box = tf.image.draw_bounding_boxes(batchced_img, boxes)

    plt.imshow(image_with_box[0].eval())
    plt.show()

    # 对原图进行随机裁剪,但是至少覆盖标注框boxes,40%的内容
    begin, size, bbox_for_draw = tf.image.sample_distorted_bounding_box(
        tf.shape(image_float), bounding_boxes=boxes, min_object_covered=0.4
    )
    print(begin)
    print(size)
    distorted_image = tf.slice(image_float, begin, size)
    plt.imshow(image_with_box[0].eval())
    plt.show()

image.png

2019-12-13 21:58:44 weixin_44586750 阅读数 26
  • 1.14.ARM裸机第十四部分-LCD显示器

    本期课程主要讲解LCD。首先讲了LCD显示原理、颜色原理、LCD显示器的主要性能参数、概念等,然后进入了LCD编程实战部分,用6节课从零开始带大家编写程序在LCD上显示像素、背景、线条、文字、图片等内容。本课程的学习目标是掌握LCD显示相关的概念和编程方法,对显存的作用和填充有本质的了解,对图像显示有一定的认识。

    8381 人正在学习 去看看 朱有鹏

一、孔洞填充

基本思想:
基于形态学算法,膨胀后与上取反的原图
在这里插入图片描述
算法实现步骤:
1.首先找出所有孔洞的位置,只需知道洞中的一个点的坐标即可,下面直接以改点代替该洞
2.新建一张全零图,用0表示背景,1表示前景,大小与原图相同
(1)取出一个洞的坐标,在新图中该位置表1
(2)对该新图用一个结构元进行膨胀,然后再与原图的反(孔洞的地方应全为1)求与
(3)如果检测到一次操作完的结果与操作前相同,则结束迭代
(4)取出下一个洞的坐标,返回到(2)操作,直到所有洞都补完
3.此时新图中为1的位置即为需要填补的孔洞,将新图与原图相或即得到孔洞填充完成的图像
注:
边缘检测:图-腐蚀后的图

代码实现:

clc;clear;
A=imread('Experiment4_tak1.png');
BW=im2bw(A);
AC=~BW;
mask=[0,1,0;1,1,1;0,1,0]; %膨胀操作的结构元
SE=strel('arbitrary',mask);
[m,n]=size(BW);
T=zeros(m,n);

%膨胀操作 某位置只要与结构元有交际,则该位置就为集合
%x0找出了所有的孔洞位置
x0={[29,24],[92,20],[187,17],[48,79],[2,91],[132,72],[92,102],[236,70],[213,117],[53,153],[122,155],[197,189],[262,181],[29,230],[119,233],[204,240],[260,250]};
for i=1:length(x0)
flag=1;
T_last=zeros(m,n);
col_temp=x0{i}(1);
row_temp=x0{i}(2);

T(row_temp,col_temp)=1; 	  %令该位置为1 然后利用模板进行膨胀
    while flag

        T=imdilate(T,SE);
        T=T∾               %将T与背景相与,注意这里T和AC用1表示需要填充的空洞即黑色局域 

        if T==T_last          %如果操作前后没有变化则认为填充完成
            flag=0;
        end
        T_last=T;
    end
end
New=BW|T;

edge=New-imerode(New,SE);

subplot(131);
imshow(BW);title('处理前');
subplot(132);
imshow(New);title('处理后');
subplot(133);
imshow(edge);title('边缘');

结果:
在这里插入图片描述

二、全局阈值

2.1 迭代阈值

基本思想:
Ti1=(小于Ti的平均灰度+大于Ti的平均灰度)/2,一直迭代到Ti1与Ti相同
在这里插入图片描述
注:
matlab默认操作的数据类型是double,所以转int时一定要慎重,一个表达式中有一个int整个表达式就是int型了!

代码实现:

clc;clear;
A=imread('Experiment4_task2.jpg');
A=rgb2gray(A);

H=imhist(A);
h=H./sum(H);
h=h';
T0=120;
error=100;

%循环或用矩阵相乘做
%这里注意表达式中存在int整个式子就默认为intwhile (error)>=1e-5
    temp1=0;
    sum1=sum(h(1:(T0+1)));
    temp2=0;
    sum2=sum(h((T0+2):256));
    for i=1:double(T0+1)
        temp1=temp1+h(i)*(i-1)/sum1;
    end
     
%     x=double(0:T0);
%     temp1=x*h(1:T0+1)'/sum(h(1:T0+1));
    
    for j=double(T0+2):256
        temp2=temp2+h(j)*(j-1)/sum2;
    end
%     y=double(T0+1:255);
%     temp2=y*h(T0+2:256)'/sum(h(T0+2:256));
    
    T1=(1/2*(temp1+temp2));
    error=abs(T1-T0);
    T0=int32(T1);
end

% while error>1
%     temp1=(find(A>T0));
%     temp2=(find(A<T0));
%     T1=1/2*(mean(A(temp1))+mean(A(temp2)));
%     error=abs(T1-T0);
%     T0=T1;
% end

[m,n]=size(A);
A1=A;
for i=1:m
    for j=1:n
        if A1(i,j)>T0
            A1(i,j)=255;
        else
            A1(i,j)=0;
        end
    end
end
str1=['迭代法 阈值为',num2str(T0)];
subplot(121);
imshow(A1);title(str1);

2.2 Otsu方法, 大津法

基本思想:
阈值从0取到255,计算每一阈值对应类间方差,取类间方差取max时的阈值
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码实现:

%otsu方法
for i=1:256
    P1=sum(h(1:i));
    P2=1-P1;
    m1=0;
    m2=0;
    for j=1:256
        if j<=i
            m1=m1+h(j)*(j-1)/P1;
        else
            m2=m2+h(j)*(j-1)/P2;
        end
    end

    op(i)=P1*P2*(m1-m2)^2;
end
t=find(op==max(op))-1;
A2=A;
for i=1:m
    for j=1:n
        if A2(i,j)>t
            A2(i,j)=255;
        else
            A2(i,j)=0;
        end
    end
end
str2=['大津法 阈值为',num2str(t)];
subplot(122);
imshow(A2);title(str2);

结果:
在这里插入图片描述

三、自适应阈值

基本思想:
如果图像光照不均匀等因素,则不能使用一个规定的全局阈值,选择的阈值时坐标的函数。

算法实现步骤:
1.将整幅图像分成一系列互相有50%重叠的子图像;
2.得到每个子图像的直方图;
3.检测各子图像是否为双峰,若是则采用最优阈值法,否则不进行处理;
4.根据对直方图为双峰的子图像得到的阈值,通过插值得到所有子图像的插值;
5.根据各子图像的阈值,然后对图像进行分割;
注:
1.这里判断双峰采用了findpeaks()函数,并规定而间距过小的峰值不算,检测到的极大值的个数超过1个则认为是双峰;
2.插值利用的是imresize()函数,直接将得到的一系列阈值模板插值得到与原图等大的阈值矩阵;
3.这里处理的具体方法为:
(1)先不管峰的个数,直接利用大津法直接得到阈值模板后插值得到阈值矩阵T;
(2)对峰的个数进行判断,如果仅有1个的话该处阈值设为0,得到阈值模板后进行插值得到阈值矩阵T1;
(3)最终的阈值模板应为T2=(T1&T).*T

代码实现:

clc;clear;
A=imread('Experiment4_task3.jpg');
A=rgb2gray(A);
[m1,n1]=size(A);
row_num=floor(m1/5);
col_num=floor(n1/5);
for i=0:(row_num-2)
    for j=0:(col_num-2)
        block=A(1+5*i:1+5*i+9,1+5*j:1+5*j+9);
        B=imhist(block);
        pks=findpeaks(B,'minpeakdistance',35);
        if length(pks)>1
            t1=255*graythresh(block);
        else
            t1=0;
        end
        t=255*graythresh(block);
        T(i+1,j+1)=t;
        T1(i+1,j+1)=t1;
    end
end
T_1=imresize(T,[m1,n1],'bilinear');
T1_1=imresize(T1,[m1,n1],'bilinear');
T2=T_1&T1_1;
T2_1=T2.*T_1;
for i=1:m1
    for j=1:n1
        if A(i,j)>T2_1(i,j)
            A(i,j)=255;
        else
            A(i,j)=0;
        end
    end
end

figure;
%进行开操作
mask=[0,1,0;1,1,1;0,1,0]; %膨胀操作的结构元
SE=strel('arbitrary',mask);
A=imerode(A,SE);
A=imdilate(A,SE)
imshow(A);

结果:
效果还行,如果把窗减得更小估计能更好,但就是跑得慢。。。
在这里插入图片描述

2016-08-11 21:36:49 qq_20823641 阅读数 13557
  • 1.14.ARM裸机第十四部分-LCD显示器

    本期课程主要讲解LCD。首先讲了LCD显示原理、颜色原理、LCD显示器的主要性能参数、概念等,然后进入了LCD编程实战部分,用6节课从零开始带大家编写程序在LCD上显示像素、背景、线条、文字、图片等内容。本课程的学习目标是掌握LCD显示相关的概念和编程方法,对显存的作用和填充有本质的了解,对图像显示有一定的认识。

    8381 人正在学习 去看看 朱有鹏


         可以说从这篇文章开始,就结束了图像识别的入门基础,来到了第二阶段的学习。在平时处理二值图像的时候,除了要进行形态学的一些操作,还有有上一节讲到的轮廓连通区域的面积周长标记等,还有一个最常见的就是孔洞的填充,opencv这里成为漫水填充,其实也可以叫种子填充,或者区域生长,基本的原理是一样的,但是应用的时候需要注意一下,种子填充用递归的办法,回溯算法,漫水填充使用堆栈,提高效率,同时还提供了一种方式是扫描行。经常用来填充孔洞,现在来具体看看。


漫水填充:也就是用一定颜色填充联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果;漫水填充经常被用来标记或分离图像的一部分以便对其进行进一步处理或分析,也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或只处理掩码指定的像素点,操作的结果总是某个连续的区域。简单的说,就是选中点seedPoint,然后选取出它周围和它色彩差异不大的点,并将它们的值改为newVal。如果被选取的点,遇到mask掩码,则放弃对该方向的

种子填充算法,种子填充算法是从多边形区域内部的一点开始,由此出发找到区域内的所有像素。种子填充算法采用的边界定义是区域边界上所有像素具有某个特定的颜色值,区域内部所有像素均不取这一特定颜色,而边界外的像素则可具有与边界相同的颜色值。

具体算法步骤:

  • 标记种子(x,y)的像素点 ;
  • 检测该点的颜色,若他与边界色和填充色均不同,就用填充色填   充该点,否则不填充 ;
  • 检测相邻位置,继续 2。这个过程延续到已经检测区域边界范围内的所有像素为止。
  • 当然在搜索的时候有两种检测相邻像素:四向连通和八向连通。四向连通即从区域上一点出发,通过四个方向上、下、左、右来检索。而八向连通加上了左上、左下、右上、右下四个方向。这种算法的有点是算法简单,易于实现,也可以填充带有内孔的平面区域。但是此算法需要更大的存储空间以实现栈结构,同一个像素多次入栈和出栈,效率低,运算量大。

扫描线种子填充算法:该算法属于种子填充算法,它是以扫描线上的区段为单位操作。所谓区段,就是一条扫描线上相连着的若干内部象素的集合。扫描线种子填充算法思想:首先填充当前扫描线上的位于给定区域的一区段,然后确定于这一区段相邻的上下两条线上位于该区域内是否存在需要填充的新区段,如果存在,则依次把他们保存起来,反复这个过程,直到所保存的各区段都填充完毕。

<span style="font-size:18px;">FloodFill函数
  C++: int floodFill(InputOutputArray image, InputOutputArray mask, 
                Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 );
  InputOutputArray:输入和输出图像。
  mask:            输入的掩码图像。
  seedPoint:      算法开始处理的开始位置。 
  newVal:         图像中所有被算法选中的点,都用这个数值来填充。
    rect:            最小包围矩阵。
  loDiff:         最大的低亮度之间的差异。
    upDiff:         最大的高亮度之间的差异。
  flag:           选择算法连接方式。
</span>

根据上面的函数先看一个基础的应用

<span style="font-size:18px;">#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;

Mat g_srcImage, g_dstImage, g_grayImage, g_maskImage;
int g_nFillMode = 1;
int g_nLowDifference = 20, g_nUpDifference = 20;
int g_nConnectivity = 4;
int g_bIsColor = true;
bool g_bUseMask = false;
int g_nNewMaskVal = 255;
static void onMouse( int event, int x, int y, int, void* )
{

	if( event != EVENT_LBUTTONDOWN )
		return;
	Point seed = Point(x,y);
	int LowDifference = g_nFillMode == 0 ? 0 : g_nLowDifference;
	int UpDifference = g_nFillMode == 0 ? 0 : g_nUpDifference;
	int flags = g_nConnectivity + (g_nNewMaskVal << 8) +(g_nFillMode == 1 ? FLOODFILL_FIXED_RANGE : 0);
	int b = (unsigned)theRNG() & 255;
	int g = (unsigned)theRNG() & 255;
	int r = (unsigned)theRNG() & 255;
	Rect ccomp;
	Scalar newVal = g_bIsColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114);
	Mat dst = g_bIsColor ? g_dstImage : g_grayImage;//目标图的赋值
	int area;
	if( g_bUseMask )
	{
		threshold(g_maskImage, g_maskImage, 1, 128, THRESH_BINARY);
		area = floodFill(dst, g_maskImage, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
			Scalar(UpDifference, UpDifference, UpDifference), flags);
		imshow( "mask", g_maskImage );
	}
	else
	{
		area = floodFill(dst, seed, newVal, &ccomp, Scalar(LowDifference, LowDifference, LowDifference),
			Scalar(UpDifference, UpDifference, UpDifference), flags);
	}

	imshow("效果图", dst);
	cout << area << " 个像素被重绘\n";
}

int main( int argc, char** argv )
{

	g_srcImage = imread("lena.jpg", 1);

	if( !g_srcImage.data ) { printf("读取图片image0错误~! \n"); return false; } 

	g_srcImage.copyTo(g_dstImage);
	cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
	g_maskImage.create(g_srcImage.rows+2, g_srcImage.cols+2, CV_8UC1);
	namedWindow( "效果图",WINDOW_AUTOSIZE );
	createTrackbar( "负差最大值", "效果图", &g_nLowDifference, 255, 0 );
	createTrackbar( "正差最大值" ,"效果图", &g_nUpDifference, 255, 0 );
	setMouseCallback( "效果图", onMouse, 0 );
	while(1)
	{
		//先显示效果图
		imshow("效果图", g_bIsColor ? g_dstImage : g_grayImage);

		//获取键盘按键
		int c = waitKey(0);
		//判断ESC是否按下,若按下便退出
		if( (c & 255) == 27 )
		{
			cout << "程序退出...........\n";
			break;
		}

		//根据按键的不同,进行各种操作
		switch( (char)c )
		{
			//如果键盘“1”被按下,效果图在在灰度图,彩色图之间互换
		case '1':
			if( g_bIsColor )//若原来为彩色,转为灰度图,并且将掩膜mask所有元素设置为0
			{
				cout << "键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】\n";
				cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
				g_maskImage = Scalar::all(0);	//将mask所有元素设置为0
				g_bIsColor = false;	//将标识符置为false,表示当前图像不为彩色,而是灰度
			}
			else//若原来为灰度图,便将原来的彩图image0再次拷贝给image,并且将掩膜mask所有元素设置为0
			{
				cout << "键盘“1”被按下,切换彩色/灰度模式,当前操作为将【彩色模式】切换为【灰度模式】\n";
				g_srcImage.copyTo(g_dstImage);
				g_maskImage = Scalar::all(0);
				g_bIsColor = true;//将标识符置为true,表示当前图像模式为彩色
			}
			break;
			//如果键盘按键“2”被按下,显示/隐藏掩膜窗口
		case '2':
			if( g_bUseMask )
			{
				destroyWindow( "mask" );
				g_bUseMask = false;
			}
			else
			{
				namedWindow( "mask", 0 );
				g_maskImage = Scalar::all(0);
				imshow("mask", g_maskImage);
				g_bUseMask = true;
			}
			break;
			//如果键盘按键“3”被按下,恢复原始图像
		case '3':
			cout << "按键“3”被按下,恢复原始图像\n";
			g_srcImage.copyTo(g_dstImage);
			cvtColor(g_dstImage, g_grayImage, COLOR_BGR2GRAY);
			g_maskImage = Scalar::all(0);
			break;
			//如果键盘按键“4”被按下,使用空范围的漫水填充
		case '4':
			cout << "按键“4”被按下,使用空范围的漫水填充\n";
			g_nFillMode = 0;
			break;
			//如果键盘按键“5”被按下,使用渐变、固定范围的漫水填充
		case '5':
			cout << "按键“5”被按下,使用渐变、固定范围的漫水填充\n";
			g_nFillMode = 1;
			break;
			//如果键盘按键“6”被按下,使用渐变、浮动范围的漫水填充
		case '6':
			cout << "按键“6”被按下,使用渐变、浮动范围的漫水填充\n";
			g_nFillMode = 2;
			break;
			//如果键盘按键“7”被按下,操作标志符的低八位使用4位的连接模式
		case '7':
			cout << "按键“7”被按下,操作标志符的低八位使用4位的连接模式\n";
			g_nConnectivity = 4;
			break;
			//如果键盘按键“8”被按下,操作标志符的低八位使用8位的连接模式
		case '8':
			cout << "按键“8”被按下,操作标志符的低八位使用8位的连接模式\n";
			g_nConnectivity = 8;
			break;
		}
	}

	return 0;
}
</span>
                                         

再来看看漫水填充在填充孔洞上的应用

#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;  
void chao_fillHole(const cv::Mat srcimage, cv::Mat &dstimage)  
{  
    Size m_Size = srcimage.size();  
    Mat temimage = Mat::zeros(m_Size.height + 2, m_Size.width + 2, srcimage.type());   
    srcimage.copyTo(temimage(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)));  
    floodFill(temimage, Point(0, 0), Scalar(255));  
    Mat cutImg;
    temimage(Range(1, m_Size.height + 1), Range(1, m_Size.width + 1)).copyTo(cutImg);  
    dstimage = srcimage | (~cutImg);  
}  
int main()  
{  
    Mat src=imread("111.png");
	Mat dst;
   chao_fillHole(src, dst)  ;
   imshow("tianchong",dst);
   waitKey(0);
   return 0;

}  
                                                                           

matlab

<span style="font-size:18px;">I=imread('tire.tif');
figure,imshow(I)
BW=imfill(I);
figure,imshow(BW)</span>


图像识别算法交流 QQ群:145076161,欢迎图像识别与图像算法,共同学习与交流


2015-11-03 20:59:34 u012300569 阅读数 581
  • 1.14.ARM裸机第十四部分-LCD显示器

    本期课程主要讲解LCD。首先讲了LCD显示原理、颜色原理、LCD显示器的主要性能参数、概念等,然后进入了LCD编程实战部分,用6节课从零开始带大家编写程序在LCD上显示像素、背景、线条、文字、图片等内容。本课程的学习目标是掌握LCD显示相关的概念和编程方法,对显存的作用和填充有本质的了解,对图像显示有一定的认识。

    8381 人正在学习 去看看 朱有鹏

介绍一下卷积:就是一种算子 

直接上例子:

[ 1 2 3 4 5 4 3 2 1] (《==原始向量)卷积 [ 2 0 -2] (《=卷积模板 )

过程:

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] (零填充)

[-2 0 2]《----[ 2 0 -2]     (翻转180度)

↓  (开始)

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

[-2 0 2]

↓ (结果 [0 2 1 2 3 4 5 4 3 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

   [-2 0 2]

↓ (结果 [0 2 4 2 3 4 5 4 3 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

      [-2 0 2]

↓ (结果 [0 2 4 4 3 4 5 4 3 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

         [-2 0 2]

↓ (结果 [0 2 4 4 4 4 5 4 3 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

            [-2 0 2]

↓ (结果 [0 2 4 4 4 4 5 4 3 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

               [-2 0 2]

↓ (结果 [0 2 4 4 4 4 0 4 3 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

                  [-2 0 2]

↓ (结果 [0 2 4 4 4 4 0 -4 3 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

                     [-2 0 2]

↓ (结果 [0 2 4 4 4 4 0 -4 -4 2 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

                        [-2 0 2]

↓ (结果 [0 2 4 4 4 4 0 -4 -4 -4 1 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

                           [-2 0 2]

↓ (结果 [0 2 4 4 4 4 0 -4 -4 -4 -4 0 0] )

[ 0 0 1 2 3 4 5 4 3 2 1 0 0] 

                              [-2 0 2]

↓ (结果 [0 2 4 4 4 4 0 -4 -4 -4 -4 -2 0] )

[0 2 4 4 4 4 0 -4 -4 -4 -4 -2 0] 《===(全部卷积结果)

[4 4 4 4 0 -4 -4 -4 -4] 《===(裁截后的卷积结果)

下面来个图片的卷积:

A卷积G


原始图片像素阵A如下:

               

1 3 2 0 4                    

1 0 3 2 3 

0 4 1 0 5 

 2 3 2 1 4

 3 1 0 4 2 

卷积模板 G

-1 0 1

-2 0 2

-1 0 1



原始图做零填充结果 9*9        

 0 0 0 0 0 0 0 0 0                   

 0 0 0 0 0 0 0 0 0                

 0 0 1 3 2 0 4 0 0                    

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

 

模板做180度翻转结果3*3

1 0 -1

2 0 -2

1 0 -1

 

开始做卷积 

第1次蓝色为模板作用区域

 0 0 0 0 0 0 0 0 0                

 0 0 0 0 0 0 0 0 0                

 0 0 1 3 2 0 4 0 0                

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

 

 

 

 

 

 

 

 

 第1次卷积结果

 0 0 0 0 0 0 0 0 0                

 0 -1 0 0 0 0 0 0 0                

 0 0 1 3 2 0 4 0 0                

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

 

第2次蓝色为模板作用区域

 0 0 0 0 0 0 0 0 0                

 0 0 0 0 0 0 0 0 0                

 0 0 1 3 2 0 4 0 0                

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

第2次卷积结果

 0 0 0 0 0 0 0 0 0                

 0 -1 -3 0 0 0 0 0 0                

 0 0 1 3 2 0 4 0 0                

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

 

第3次蓝色为模板作用区域

 0 0 0 0 0 0 0 0 0                

 0 0 0 0 0 0 0 0 0                

 0 0 1 3 2 0 4 0 0                

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

 

 

第3次卷积结果

 0 0 0 0 0 0 0 0 0                

 0 -1 -3 -1 0 0 0 0 0                

 0 1 3 2 0 4 0 0                

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

 

。。。。。。。。经过漫长的模板移动。。。。。。。。。。

 

第49次蓝色为模板作用区域

 0 0 0 0 0 0 0 0 0                

 0 0 0 0 0 0 0 0 0                

 0 0 1 3 2 0 4 0 0                

 0 0 1 0 3 2 3 0 0

 0 0 0 4 1 0 5 0 0

 0 0 2 3 2 1 4 0 0

 0 0 3 1 0 4 2 0 0

 0 0 0 0 0 0 0 0 0 

 0 0 0 0 0 0 0 0 0

第49次卷积结果

 0 0  0  0  0  0  0  0  0                

 0 -1  -3 -1 -3  -2  0  4  0                

 0 -3  -6  -4  4  -4  2  11  0                

 0 -3  -7  -6  3  -6  2  15  0

 0 -3  -11 -4 8 -10  3  17  0

 0 -7 -11  2  5 -10  6  15  0

 0 -8  -5  6 -4  -6  9  8  0

 0 3  1  3  -3  -2  4  2  0 

 0 0  0  0  0  0  0  0  0

 

裁截后的卷积结果

              

-6  -4  4  -4  2             

-7  -6  3  -6  2

-11 -4  8 -10  3  

-11  2  5 -10  6  

-5  6 -4  -6  9  




2019-06-08 21:17:34 nanhuaibeian 阅读数 930
  • 1.14.ARM裸机第十四部分-LCD显示器

    本期课程主要讲解LCD。首先讲了LCD显示原理、颜色原理、LCD显示器的主要性能参数、概念等,然后进入了LCD编程实战部分,用6节课从零开始带大家编写程序在LCD上显示像素、背景、线条、文字、图片等内容。本课程的学习目标是掌握LCD显示相关的概念和编程方法,对显存的作用和填充有本质的了解,对图像显示有一定的认识。

    8381 人正在学习 去看看 朱有鹏

一、为什么要补零?

卷积定理
在这里插入图片描述
空间滤波由滤波器模板 h(x,y) 卷积一幅图像 f(x,y) 组成。
根据卷积定理,在频率域中让 F(x,y) 乘以空间滤波器的傅里叶变换 H(u,v), 可得到相同的结果。
但在处理离散量时,我们知道 F 和 H 都是周期的,这表明在离散频率域中执行的卷积也是周期的。因此用 DFT 执行的卷积称为循环卷积
而保证空间和循环卷积给出相同结果的唯一方法,就是使用适当地零填充。

进一步解释:
由卷积定理可知,在空间域要得到相应的滤波后的图像,就需要计算乘积 H(u,v)F(u,v) 的傅里叶反变换,当处理 DFT 进行滤波操作时,图像及其变换都是周期的。不难发现,如果关于周期的非零部分的持续时间很靠近,则对周期函数执行卷积会导致相邻周期之间的干扰,这种称为折叠误差的干扰,可以通过补零方法来避免

二、如何补零

在这里插入图片描述
使用paddedsize函数计算满足前述等式的P和Q的最小偶数值
[ 使用偶数数组可以加快 FFT 计算的速度 ]

FFT 算法的执行时间大致取决于 P 和 Q 中原始参数的数量,通常当 P 和 Q 为2的幂时,这些算法的执行速度要比原始参数时快

% 代码中,向量 AB CD 和 PQ 分别含有元素 [A B][C D][P Q]
function PQ = paddedsize(AB, CD, PARAM)
%PADDEDSIZE 计算用于基于FFT的过滤的填充大小
%   PQ = PADDEDSIZE(AB), where AB is a two-element size vector,
%   computes the two-element size vector PQ = 2*AB.
%   PQ = PADDEDSIZE(AB, 'PWR2') computes the vector PQ such that
%   PQ(1) = PQ(2) = 2^nextpow2(2*m), where m is MAX(AB).
%
%   PQ = PADDEDSIZE(AB, CD), where AB and CD are two-element size
%   vectors, computes the two-element size vector PQ.  The elements
%   of PQ are the smallest even integers greater than or equal to 
%   AB + CD - 1.
%
%   PQ = PADDEDSIZE(AB, CD, 'PWR2') computes the vector PQ such that
%   PQ(1) = PQ(2) = 2^nextpow2(2*m), where m is MAX([AB CD]). 
% nargin 输入到函数中的参量的实际数量
if nargin == 1
   PQ  = 2*AB;
elseif nargin == 2 & ~ischar(CD)	% 若 s 是字符串,则函数 ischar(s) 返回真
   PQ = AB + CD - 1;
   PQ = 2 * ceil(PQ / 2);
elseif nargin == 2
   m = max(AB); % Maximum dimension.
   
   % Find power-of-2 at least twice m.
   P = 2^nextpow2(2*m);
   PQ = [P, P];
elseif nargin == 3
   m = max([AB CD]); % Maximum dimension.
   P = 2^nextpow2(2*m);	% p = nextpow2(n) 返回大于或等于n的绝对值的2的最小整数次幂
   PQ = [P, P];
else 
   error('Wrong number of inputs.')
end

该语法会对 f 附加足够的零,以便结果图像的尺寸是 PQ(1) x PQ(2)
当 f 被填充后,频率域中的滤波器函数尺寸也必须是 PQ(1) x PQ(2)

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