2019-09-05 19:41:26 lengo 阅读数 700
  • OpenGL萌谷手册视频教程

    OpenGL视频培训课程,本课程带领完全没有基础的学员打下坚实的OpenGL学习基础,内容包括OPenGL框架搭建、矩阵、光照、纹理、3D模型绘制、键盘鼠标、模型渲染、纹理贴图等详细内容。

    12934 人正在学习 去看看 杨振

主函数:

clc;
clear all;
close all;
%纹理分割测试图像
I=im2double(imread('D:\Gray Files\9-43.tif'));
%获得图像大小
[M,N]=size(I);
%灰度闭操作
r=31;
J_Closing=GrayscaleClosing(I,r);
%灰度开操作
r=60;
J_Opening=GrayscaleOpening(J_Closing,r);
%灰度梯度
n=3;
J_Gradient=GrayscalGradient(J_Opening,n);
J=I+J_Gradient;
imshow(J)

灰度闭操作

GrayscaleClosing函数如下:

%灰度闭操作
% I 输入图像
% n 单一结构元素矩阵的大小
function J_GrayscaleClosing=GrayscaleClosing(I,r) 

    n_B=2*(r-1)+1;
    B=ones(n_B,n_B);
    %将距离大于40的点置零
    for i=1:n_B
        for j=1:n_B
            d=sqrt((i-r)^2+(j-r)^2);
            if d>r
                B(i,j)=0;
            end
        end
    end
    
    ind=find(B==0);
    n_l=floor(n_B/2);
    [M,N]=size(I); 
    J_GrayscaleClosing=zeros(M,N);  
    I_pad=padarray(I,[n_l,n_l],'symmetric');
       
    %膨胀图像
    J_Dilation=zeros(M,N);
    for i=1:M
        for j=1:N
            %获得图像子块区域
            Block=I_pad(i:i+2*n_l,j:j+2*n_l);
            C=Block.*B;
            %删除0值,保留4连通数值
            C=C(:);
            C(ind)=[];
            J_Dilation(i,j)=max(C);
        end
    end
    %对膨胀图像进行扩展
    J_Dilation_pad=padarray(J_Dilation,[n_l,n_l],'symmetric');
    %腐蚀操作
    for i=1:M
        for j=1:N
            %获得图像子块区域
            Block=J_Dilation_pad(i:i+2*n_l,j:j+2*n_l);
            C=Block.*B;
            %删除0值,保留4连通数值
            C=C(:);
            C(ind)=[];
            J_GrayscaleClosing(i,j)=min(C);
        end
    end
end

灰度开操作

GrayscaleOpening函数如下:

%灰度开操作
% I 输入图像
% n 单一结构元素矩阵的大小
function J_GrayscaleOpening=GrayscaleOpening(I,r)
    n_B=2*(r-1)+1;
    B=ones(n_B,n_B);
    %将距离大于40的点置零
    for i=1:n_B
        for j=1:n_B
            d=sqrt((i-r)^2+(j-r)^2);
            if d>r
                B(i,j)=0;
            end
        end
    end
    ind=find(B==0);
    n_l=floor(n_B/2);
    I_pad=padarray(I,[n_l,n_l],'symmetric');
    [M,N]=size(I);

    %-------------------------------灰度开操作---------------------------------
    J_GrayscaleOpening=zeros(M,N);
    %腐蚀操作
    J_Erosion=zeros(M,N);
    for i=1:M
        for j=1:N
            %获得图像子块区域
            Block=I_pad(i:i+2*n_l,j:j+2*n_l);
            C=Block.*B;
            %删除0值,保留4连通数值
            C=C(:);
            C(ind)=[];
            J_Erosion(i,j)=min(C);
        end
    end
    %对腐蚀图像进行扩展
    J_Erosion_pad=padarray(J_Erosion,[n_l,n_l],'symmetric');
    %膨胀图像
    for i=1:M
        for j=1:N
            %获得图像子块区域
            Block=J_Erosion_pad(i:i+2*n_l,j:j+2*n_l);
            C=Block.*B;
            %删除0值,保留4连通数值
            C=C(:);
            C(ind)=[];
            J_GrayscaleOpening(i,j)=max(C);
        end
    end
end

灰度梯度

GrayscalGradient函数如下:

%灰度梯度
% I 输入图像
% n 结构元素大小
function J_Gradient=GrayscalGradient(I,n)
    B=ones(n,n);
    n_l=floor(n/2);
    %对边界图进行扩充,目的是为了处理边界点,这里采用边界镜像扩展
    I_pad=padarray(I,[n_l,n_l],'symmetric');
    [M,N]=size(I);
    J_Erosion=zeros(M,N);
    J_Dilation=zeros(M,N);
    J_Gradient=zeros(M,N);
    for i=1:M
        for j=1:N
            %获得图像子块区域
            Block=I_pad(i:i+2*n_l,j:j+2*n_l);
            C=Block.*B;
            C=C(:);
            %腐蚀操作
            J_Erosion(i,j)=min(C);
            %膨胀操作
            J_Dilation(i,j)=max(C);
            %灰度梯度
            J_Gradient(i,j)=J_Dilation(i,j)-J_Erosion(i,j);
        end
    end
end

 

2019-04-24 17:42:29 weixin_43276913 阅读数 596
  • OpenGL萌谷手册视频教程

    OpenGL视频培训课程,本课程带领完全没有基础的学员打下坚实的OpenGL学习基础,内容包括OPenGL框架搭建、矩阵、光照、纹理、3D模型绘制、键盘鼠标、模型渲染、纹理贴图等详细内容。

    12934 人正在学习 去看看 杨振

旋转不变性:图像旋转时,所选特征不随图像的旋转而发生变化

LBP参考:

LBP纹理特征提取

灰度不变性-旋转不变性

import numpy as np
from PIL import Image
import math  

def LBP(src):
    '''
    :param src:灰度图像
    :rtype:灰度图像
    '''
    src = np.array(src)
    height = src.shape[0]
    width = src.shape[1]
    dst = src.copy()

    lbp_value = np.zeros((1,8), dtype=np.uint8)
    neighbours = np.zeros((1,8), dtype=np.uint8)
    # height as row, width as column
    for x in range(1, width-1):
        for y in range(1, height-1):
            neighbours[0, 0] = src[y - 1, x - 1]
            neighbours[0, 1] = src[y - 1, x]
            neighbours[0, 2] = src[y - 1, x + 1]
            neighbours[0, 3] = src[y, x - 1]
            neighbours[0, 4] = src[y, x + 1]
            neighbours[0, 5] = src[y + 1, x - 1]
            neighbours[0, 6] = src[y + 1, x]
            neighbours[0, 7] = src[y + 1, x + 1]

            center = src[y, x]

            for i in range(8):
                if neighbours[0, i] > center:
                    lbp_value[0, i] = 1
                else:
                    lbp_value[0, i] = 0

            lbp = lbp_value[0, 0] * 1 + lbp_value[0, 1] * 2 + lbp_value[0, 2] * 4 + lbp_value[0, 3] * 8 \
                + lbp_value[0, 4] * 16 + lbp_value[0, 5] * 32 + lbp_value[0, 6] * 64 + lbp_value[0, 0] * 128

            dst[y, x] = lbp
    dst = Image.fromarray(dst)
    return dst

def circular_LBP(src, radius, n_points):
    src = np.array(src)
    height = src.shape[0]
    width = src.shape[1]
    dst = src.copy()
    src.astype(dtype=np.float32)
    dst.astype(dtype=np.float32)

    neighbours = np.zeros((1, n_points), dtype=np.uint8)
    lbp_value = np.zeros((1, n_points), dtype=np.uint8)
    for x in range(radius, width - radius - 1):
        for y in range(radius, height - radius - 1):
            lbp = 0.
            # 先计算共n_points个点对应的像素值,使用双线性插值法
            for n in range(n_points):
                theta = float(2 * np.pi * n) / n_points
                x_n = x + radius * np.cos(theta)
                y_n = y - radius * np.sin(theta)

                # 向下取整
                x1 = int(math.floor(x_n))
                y1 = int(math.floor(y_n))
                # 向上取整
                x2 = int(math.ceil(x_n))
                y2 = int(math.ceil(y_n))

                # 将坐标映射到0-1之间
                tx = np.abs(x - x1)
                ty = np.abs(y - y1)

                # 根据0-1之间的x,y的权重计算公式计算权重
                w1 = (1 - tx) * (1 - ty)
                w2 = tx * (1 - ty)
                w3 = (1 - tx) * ty
                w4 = tx * ty

                # 根据双线性插值公式计算第k个采样点的灰度值
                neighbour = src[y1, x1] * w1 + src[y2, x1] * w2 + src[y1, x2] * w3 + src[y2, x2] * w4

                neighbours[0, n] = neighbour

            center = src[y, x]

            for n in range(n_points):
                if neighbours[0, n] > center:
                    lbp_value[0, n] = 1
                else:
                    lbp_value[0, n] = 0

            for n in range(n_points):
                lbp += lbp_value[0, n] * 2**n

            # 转换到0-255的灰度空间,比如n_points=16位时结果会超出这个范围,对该结果归一化
            dst[y, x] = int(lbp / (2**n_points-1) * 255)
    dst = Image.fromarray(dst)
    return dst

def value_rotation(num):
    value_list = np.zeros((8), np.uint8)
    temp = int(num)
    value_list[0] = temp
    for i in range(7):
        temp = ((temp << 1) | (temp / 128)) % 256
        value_list[i+1] = temp
    #print value_list
    return np.min(value_list)

def rotation_invariant_LBP(src):
    src = np.array(src)
    height = src.shape[0]
    width = src.shape[1]
    dst = src.copy()

    lbp_value = np.zeros((1, 8), dtype=np.uint8)
    neighbours = np.zeros((1, 8), dtype=np.uint8)
    for x in range(1, width - 1):
        for y in range(1, height - 1):
            neighbours[0, 0] = src[y - 1, x - 1]
            neighbours[0, 1] = src[y - 1, x]
            neighbours[0, 2] = src[y - 1, x + 1]
            neighbours[0, 3] = src[y, x - 1]
            neighbours[0, 4] = src[y, x + 1]
            neighbours[0, 5] = src[y + 1, x - 1]
            neighbours[0, 6] = src[y + 1, x]
            neighbours[0, 7] = src[y + 1, x + 1]

            center = src[y, x]

            for i in range(8):
                if neighbours[0, i] > center:
                    lbp_value[0, i] = 1
                else:
                    lbp_value[0, i] = 0

            lbp = lbp_value[0, 0] * 1 + lbp_value[0, 1] * 2 + lbp_value[0, 2] * 4 + lbp_value[0, 3] * 8 \
                  + lbp_value[0, 4] * 16 + lbp_value[0, 5] * 32 + lbp_value[0, 6] * 64 + lbp_value[0, 0] * 128

            # 旋转不变值
            dst[y, x] = value_rotation(lbp)
    dst = Image.fromarray(dst)
    return dst

if __name__ == '__main__':
    I = Image.open('./test/130014.jpg').convert('L')
    I.show()
    I_lbp = LBP(I)
    I_lbp.show()
    I_lbp_circle = circular_LBP(I, 2, 16)
    I_lbp_circle.show()
    I_lbp_rotate_invariant = rotation_invariant_LBP(I)
    I_lbp_rotate_invariant.show()

2018-06-06 18:11:06 qq_23926575 阅读数 10057
  • OpenGL萌谷手册视频教程

    OpenGL视频培训课程,本课程带领完全没有基础的学员打下坚实的OpenGL学习基础,内容包括OPenGL框架搭建、矩阵、光照、纹理、3D模型绘制、键盘鼠标、模型渲染、纹理贴图等详细内容。

    12934 人正在学习 去看看 杨振

提取方法:
灰度共生矩阵-python
灰度梯度共生矩阵–python

纹理特征

纹理特征刻画了图像中重复出现的局部模式与他们的排列规则,常用于图像分类和场景识别。其只能反映物体表面的特性,无法完全反映出物体的本质属性,所以仅仅利用纹理特征无法获得图像的高层次内容。
优点
1. 具有旋转不变性
2. 具有良好的抗噪性能。
缺点
1. 当图像的分辨率变化的时候,所计算出来的纹理可能会有较大偏差
2. 有可能受到光照、反射情况的影响
3. 从2-D图像中反映出来的纹理不一定是3-D物体表面真实的纹理

常用的纹理特征提取方法一般分为四大类:
1.基于统计的方法:灰度共生矩阵、灰度行程统计、灰度差分统计、局部灰度统计、半方差图、自相关函数等
优点:方法简单,易于实现。
缺点:无法利用全局信息,与人类视觉模型不匹配;计算复杂度较高,计算耗时。

较为经典的算法为灰度共生矩阵方法,其通过统计不同灰度值对的共现频率得到灰度共生矩阵,基于矩阵可计算出14种统计量:能量、熵、对比度、均匀性、相关性、方差、和平均、和方差、和熵、差方差、差平均、差熵、相关信息测度以及最大相关系数。
灰度梯度共生矩阵将图梯度信息加入到灰度共生矩阵中,综合利用图像的灰度与梯度信息,效果更好。图像的梯度信息一般通过梯度算子(也称边缘检测算子)提取,如sobel、canny、reborts等。

2.基于模型的方法:同步自回归模型、马尔可夫模型、吉布斯模型、滑动平均模型、复杂网络模型等
3.基于结构的方法:句法纹理分析、数学形态学法、Laws纹理测量、特征滤波器等
4.基于信号处理的方法:Radon变换、离散余弦变换、局部傅里叶变化、Gabor变换、二进制小波变换、树形小波分解等

参考:
灰度共生矩阵(GLCM)附Python代码
图像纹理特征总体简述

2015-12-02 19:49:37 GarfieldEr007 阅读数 1340
  • OpenGL萌谷手册视频教程

    OpenGL视频培训课程,本课程带领完全没有基础的学员打下坚实的OpenGL学习基础,内容包括OPenGL框架搭建、矩阵、光照、纹理、3D模型绘制、键盘鼠标、模型渲染、纹理贴图等详细内容。

    12934 人正在学习 去看看 杨振

第十七章 纹理分析

目录

1.    引言

2.    纹理的统计特征

3.    基于纹理的分割

作业


1. 引言

     纹理是对图象的象素灰度级在空间上的分布模式的描述,反映物品的质地,如粗糙度、光滑性、颗粒度、随机性和规范性等。当图象中大量出现同样的或差不多的基本图象元素(模式)时,纹理分析是研究这类图象的最重要的手段之一,此外分形方法也十分重要[2]。

   

     描述一块图象区域的纹理有三种主要的方法,统计分析方法、结构分析方法和频谱分析方法[1]。

     统计方法有自相关函数、纹理边缘、结构元素、灰度的空间共生概率(spatialgray-tone cooccurrence probabilities)、灰度行程和自回归模型。统计方法将纹理描述为光滑、粗糙、粒状等等。

     结构方法研究基元及其空间关系。基元一般定义为具有某种属性而彼此相连的单元的集合,属性包括灰度、连通区域的形状、局部一致性等。空间关系包括基元的相邻性、在一定角度范围内的最近距离等等。根据基元间的空间联系,纹理可以分为弱纹理或强纹理。进一步细分,可以根据基元的空间共生频率来划分,也可以根据单位面积内的边缘数来区别。基元也可以定义为灰度行程。

     频谱方法是根据傅立叶频谱,根据峰值所占的能量比例将图象分类。包括计算峰值处的面积、峰值处的相位、峰值与原点的距离平方、两个峰值间的相角差等手段。

2. 纹理的统计特征

·        共生矩阵

共生矩阵用两个位置的象素的联合概率密度来定义,它不仅反映亮度的分布特性,也反映具有同样亮度或接近亮度的象素之间的位置分布特性,是有关图象亮度变化的二阶统计特征。它是定义一组纹理特征的基础。

    如下图所示,定义位置算子:

假设给定如下的仅具有3个灰度级的图象区域,分别记数符合上述位置算子的象素空间组合的数目形成频度矩阵,再将其归一化,即除以符合位置关系的总数就得到共生矩阵。共生矩阵的阶数与图象的灰度级别数相等。

 

 
 

 

 
 

 

 
 

 

·        基于共生矩阵的纹理特征

    选择合适的位置算子,计算出共生矩阵,然后可以计算如下的纹理描述特征:

 
 

 

3. 基于纹理的分割

    将图象分割成一些具有某种一致性的区域是图象分析的重要手段,一致性包括亮度、颜色或纹理等衡量标准。在机器视觉系统中,通常图象可以根据亮度标准进行分割,但在复杂的情况下,如自然景物,这种方法不能达到令人满意的分割效果。因为这类图象不具有均匀的亮度分布,而具有共同的纹理特征。

 图片来自Extractionof Textured Regions

    如果在没有任何先验知识以及任何统计训练数据可以利用的情况下,可以采用如下的基于共生矩阵的纹理分割方法。

    例如,对于256x256大小的原图象,随机地选择40个NxN子图象,N需要根据实验来确定。记图象的灰度级数目是G,根据这些子图象计算各自的共生矩阵(GxG)。然后,将共生矩阵分成n等份方形子矩阵,用子矩阵元素的平均值形成一n维特征向量。根据它们在Rn特征空间的聚类情况,将图象分成不同的纹理区域。

    在纹理分析中,Gabor变换是一种常用的重要工具,具有十分重要的作用。有关Gabor变换的基本概念在第12章第5节有介绍,更为深入的内容读者可以参照网上的相关资料(GaborFilters for Texture (links) ..\..\download_IPCVPR\textureanalysis\USC GaborFilters for Texture.htm)。

    此外,分形技术在图象纹理分割中具有十分重要的应用,参见:杨波 徐光佑 朱志刚,基于分形特征的自然景物图象分割方法,中国图象图形学报,1999。

网上资源:

1.    MilanSonka Chapter 13, Texture

2.    Vision Texturehomepage

3.    TextureEnergies for 1D Rays

4.    TextureAnalysis Methods (links)

5.    Extractionof Textured Regions

6.    Whatis Texture ?

7.    GaborFilters for Texture (links)

参考文献

1.    Sing-Tze Bow, Pattern recognition and image preprocessing, M.Dekker, New York, 1992

2.    Ning Lu, Fractal imaging, Academic Press, San Diego, 1997

作业

1.    编制基于统计方法的基于共生矩阵的纹理分割程序。图片在目录:./Images/textures

致谢

    我要特别感谢清华大学计算机系的博士研究生杨波,他提供了一些素材。


返回主目录 返回本章目录

清华大学计算机系 艾海舟

最近修改时间:2001年7月19日

出处:http://media.cs.tsinghua.edu.cn/~ahz/digitalimageprocess/CourseImageProcess.html

2015-10-26 16:54:51 zjsyhsl 阅读数 1062
  • OpenGL萌谷手册视频教程

    OpenGL视频培训课程,本课程带领完全没有基础的学员打下坚实的OpenGL学习基础,内容包括OPenGL框架搭建、矩阵、光照、纹理、3D模型绘制、键盘鼠标、模型渲染、纹理贴图等详细内容。

    12934 人正在学习 去看看 杨振

1 最近在看CUDA优化,看到纹理内存部分,可以使用纹理内存加速。
可是使用纹理内存后图像的处理速度反而变慢了。不解????

2 使用纹理内存代码
//Sobel 边缘提取 使用纹理内存

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>
#include<iostream>
#include"opencv2\opencv.hpp"

using namespace std;
using namespace cv;

//声明纹理参考系
texture<uchar,2,cudaReadModeElementType> tex;//2d texture

//设备端kernel函数
__global__ void ImgEdge_3x3_S_kernel(uchar* pImgOut,
                                       int nWidth,
                                       int nHeight,
                                       int nWidthStep)
{
    const int ix=blockIdx.x*blockDim.x+threadIdx.x;
    const int iy=blockIdx.y*blockDim.y+threadIdx.y;
    int point=ix+iy*nWidthStep;


    if(ix<nWidth&&iy<nHeight)
    {

        uchar point00=tex2D(tex,(float)ix-1,(float)iy-1);
        uchar point01=tex2D(tex,(float)ix,(float)iy-1);
        uchar point02=tex2D(tex,(float)ix+1,(float)iy-1);
        uchar point10=tex2D(tex,(float)ix-1,(float)iy);
        uchar point11=tex2D(tex,(float)ix,(float)iy);
        uchar point12=tex2D(tex,(float)ix+1,(float)iy);
        uchar point20=tex2D(tex,(float)ix-1,(float)iy+1);
        uchar point21=tex2D(tex,(float)ix,(float)iy+1);
        uchar point22=tex2D(tex,(float)ix+1,(float)iy+1);
        int Horz=point02+2*point12+point22-point00-2*point10-point20;
        int Vert=point00+2*point01+point02-point20-2*point21-point22;
        int Sum=abs(Horz)+abs(Vert);
        if(Sum>255) pImgOut[point]=255;
        else pImgOut[point]=(uchar)Sum;

    }
}
//设备端代码
double cudaImgEdge(uchar* pImgOut,
                     uchar* pImgIn,
                     int nWidth,
                     int nHeight,
                     int nWidthStep,
                     int nChannels)
{

    //准备设备端空间
    uchar* d_pImgInGPU;
    uchar* d_pImgOutGPU;
    cudaMalloc((void**)&d_pImgInGPU,nWidthStep*nHeight*sizeof(uchar));
    cudaMalloc((void**)&d_pImgOutGPU,nWidthStep*nHeight*sizeof(uchar));
    //数据初始化
    cudaMemcpy(d_pImgInGPU,pImgIn,nWidthStep*nHeight*sizeof(uchar),cudaMemcpyHostToDevice);
    cudaMemset(d_pImgOutGPU,0,nWidthStep*nHeight*sizeof(uchar));
    //建立CUDA二维数组
    cudaArray* cuArray;
    cudaChannelFormatDesc channelDesc=cudaCreateChannelDesc<uchar>();//CUDA数组的描述(组件数量和数据类型)
    cudaMallocArray(&cuArray,&channelDesc,nWidth,nHeight);
    cudaMemcpyToArray(cuArray,0,0,pImgIn,sizeof(uchar)*nWidth*nHeight,cudaMemcpyHostToDevice);
    //tex.AddressMode[0]=cudaAddressModeWrap;
    //tex.AddressMode[1]=cudaAddressModeWrap;
    //tex.normalized=true;
    //将显存数据与纹理绑定
    cudaBindTextureToArray(&tex,cuArray,&channelDesc);

    //启动kernel进行并行处理
    dim3 threads(16,16);
    dim3 grid((nWidth*nChannels+threads.x-1)/threads.x,(nHeight+threads.y-1)/threads.y);
    ImgEdge_3x3_S_kernel<<<grid,threads>>>(d_pImgOutGPU,nWidth,nHeight,nWidthStep);
    //解绑定
    cudaUnbindTexture(tex);
    cudaFreeArray(cuArray);
    //数据输出
    cudaMemcpy(pImgOut,d_pImgOutGPU,nWidthStep*nHeight*sizeof(uchar),cudaMemcpyDeviceToHost);
    //释放空间
    cudaFree(d_pImgInGPU);
    cudaFree(d_pImgOutGPU);
    return 0;
}

int main()
{
    //读入图片
    Mat ImgIn=imread("D:\\Images\\lenna1024.bmp",0);
    //检查是否成功
    if(ImgIn.empty())
    {
        cout<<"Can not load image"<<endl;
        return -1;
    }
    //读取图片数据结构
    Mat ImgOut=ImgIn.clone();
    int nWidth=ImgIn.cols;
    int nHeight=ImgIn.rows;
    int nWidthStep=ImgIn.step;
    int nChannels=ImgIn.channels();
    uchar* pSrc=ImgIn.data;
    uchar* pDest=ImgOut.data;

    //记录时间事件
    cudaEvent_t start,stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord(start,0);//开始时刻

    //调用边缘检测函数处理图片
    cudaImgEdge(pDest,pSrc,nWidth,nHeight,nWidthStep,nChannels);

    cudaEventRecord(stop,0);//结束时刻
    cudaEventSynchronize(stop);
    float elapsedTime;
    cudaEventElapsedTime(&elapsedTime,start,stop);
    printf("Time to generate:%f ms\n",elapsedTime);
    cudaEventDestroy(start);
    cudaEventDestroy(stop);

    //显示图片
    imshow("ImgIn",ImgIn);
    imshow("ImgOut",ImgOut);
    waitKey(0);
    return 0;
}

结果一个1024X1024的图像运行时间为127ms

3 未使用纹理内存代码

//Sobel 边缘提取 未使用纹理内存

#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>
#include<time.h>
#include"opencv2\opencv.hpp"

using namespace std;
using namespace cv;


//设备端kernel函数
__global__ void ImgEdge_3x3_Sobel_kernel(uchar* pImgOut,
                                       uchar* pImgIn,
                                       int nWidth,
                                       int nHeight,
                                       int nWidthStep)
{
    const int ix=blockIdx.x*blockDim.x+threadIdx.x;
    const int iy=blockIdx.y*blockDim.y+threadIdx.y;

    const int ix_1=max(0,ix-1);
    const int ix1=min(nWidth-1,ix+1);
    const int iy_1=max(0,iy-1);
    const int iy1=min(nHeight-1,iy+1);

    if(ix<nWidth&&iy<nHeight)
    {

        uchar point00=pImgIn[iy_1*nWidthStep+ix_1];
        uchar point01=pImgIn[iy_1*nWidthStep+ix];
        uchar point02=pImgIn[iy_1*nWidthStep+ix1];
        uchar point10=pImgIn[iy*nWidthStep+ix_1];
        uchar point11=pImgIn[iy*nWidthStep+ix];
        uchar point12=pImgIn[iy*nWidthStep+ix1];
        uchar point20=pImgIn[iy1*nWidthStep+ix_1];
        uchar point21=pImgIn[iy1*nWidthStep+ix];
        uchar point22=pImgIn[iy*nWidthStep+ix1];
        int Horz=point02+2*point12+point22-point00-2*point10-point20;
        int Vert=point00+2*point01+point02-point20-2*point21-point22;
        int Sum=abs(Horz)+abs(Vert);
        if(Sum>255) pImgOut[iy*nWidthStep+ix]=255;
        else pImgOut[iy*nWidthStep+ix]=(uchar)Sum;

    }
}
//主机端函数
double cudaImgEdge(uchar* pImgOut,
                     uchar* pImgIn,
                     int nWidth,
                     int nHeight,
                     int nWidthStep,
                     int nChannels)
{

    //准备设备端空间
    uchar* d_pImgInGPU;
    uchar* d_pImgOutGPU;
    cudaMalloc((void**)&d_pImgInGPU,nWidthStep*nHeight*sizeof(uchar));
    cudaMalloc((void**)&d_pImgOutGPU,nWidthStep*nHeight*sizeof(uchar));
    //数据初始化
    cudaMemcpy(d_pImgInGPU,pImgIn,nWidthStep*nHeight*sizeof(uchar),cudaMemcpyHostToDevice);
    cudaMemset(d_pImgOutGPU,0,nWidthStep*nHeight*sizeof(uchar));


    //启动kernel进行并行处理
    dim3 threads(16,16);
    dim3 grid((nWidth*nChannels+threads.x-1)/threads.x,(nHeight+threads.y-1)/threads.y);
    ImgEdge_3x3_Sobel_kernel<<<grid,threads>>>(d_pImgOutGPU,d_pImgInGPU,nWidth,nHeight,nWidthStep);


    //数据输出
    cudaMemcpy(pImgOut,d_pImgOutGPU,nWidthStep*nHeight*sizeof(uchar),cudaMemcpyDeviceToHost);


    //释放空间
    cudaFree(d_pImgInGPU);
    cudaFree(d_pImgOutGPU);
    return 0;
}

int main()
{

    //读入图片
    Mat ImgIn=imread("D:\\Images\\lenna1024.bmp",0);
    //检查是否成功
    if(ImgIn.empty())
    {
        cout<<"Can not load image"<<endl;
        return -1;
    }
    //读取图片数据结构
    Mat ImgOut=ImgIn.clone();
    int nWidth=ImgIn.cols;
    int nHeight=ImgIn.rows;
    int nWidthStep=ImgIn.step;
    int nChannels=ImgIn.channels();
    uchar* pSrc=ImgIn.data;
    uchar* pDest=ImgOut.data;

    //记录时间事件
    cudaEvent_t start,stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord(start,0);//开始时刻

    //调用边缘检测函数处理图片
    cudaImgEdge(pDest,pSrc,nWidth,nHeight,nWidthStep,nChannels);

    cudaEventRecord(stop,0);//结束时刻
    cudaEventSynchronize(stop);
    float elapsedTime;
    cudaEventElapsedTime(&elapsedTime,start,stop);
    printf("Time to generate:%f ms\n",elapsedTime);
    cudaEventDestroy(start);
    cudaEventDestroy(stop);

    //显示图片
    imshow("ImgIn",ImgIn);
    imshow("ImgOut",ImgOut);

    waitKey(0);
    return 0;
}

同样的图片时间为17ms.

不知道使用的对不对。。

图像纹理特征总体简述

博文 来自: ajianyingxiaoqinghan
没有更多推荐了,返回首页