2019-11-19 23:47:23 qq_36511401 阅读数 1165
  • Android App性能调优、内存泄露检测

    本课程属于Android的部分,主要讲解Android性能调优的多种方式(如通过Android手机自身的工具,算法优化、严格模式等),以及如何用不同的工具检测出内存泄露点。学员通过本课程的学员,可以达到Android开发的阶段。

    10949 人正在学习 去看看 李宁

底下有详细代码

一、介绍

1、图像检测的原理。

        图像检测的原理是检测相邻的几个点像素值之间的变化率,相对于对函数求导。求点P(x,y)的变换率,可以在点P周围选取一些点,求x方向的距离Gx,再求y方向上的距离Gy。最后变换率G等于Gx平方加上Gy平方的和的平方差,即G=Math.sqrt(Gx^2+Gy^2)。

2、Sobel算子。

        索贝尔算子对噪声不敏感。是计算机视觉领域的一种重要处理方法。主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。索贝尔算子是把图像中每个像素的上下左右四领域的灰度值加权差,在边缘处达到极值从而检测边缘。
        索贝尔算子主要用作边缘检测。在技术上,它是一离散性差分算子,用来运算图像亮度函数的梯度之近似值。在图像的任何一点使用此算子,将会产生对应的梯度矢量或是其法矢量。
        索贝尔算子不但产生较好的检测效果,而且对噪声具有平滑抑制作用,但是得到的边缘较粗,且可能出现伪边缘。

3、Sobel算子模版。

        Gx=f(x+1,y-1)+2f(x+1,y)+f(x+1,y+1)-(f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1))
        Gy=f(x-1,y+1)+2f(x,y+1)+f(x+1,y+1)-(f(x-1,y-1)+2f(x,y-1)+f(x+1,y-1))
        Gx=[-1 0  1] , Gy=[-1 -2 -1]
               [-2 0  2]         [ 0  0  0]
               [-1 0  1]         [ 1  2  1]

二、主要代码

1、EdgeDetectionTest 类。

package com.zxj.reptile.test.image.edge;

import com.zxj.reptile.utils.image.EdgeDetectionUtils;
import com.zxj.reptile.utils.image.ImageService;
import com.zxj.reptile.utils.image.ImageUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

/**
 * 图像边缘检测
 */
public class EdgeDetectionTest {
    public static void main(String[] args) {
        sobelTest();
    }

    private static void sobelTest() {
        String sourcePath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena灰度图.jpg";
        String targetPath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena-sobel.jpg";
        sobel(sourcePath, targetPath);
        sobelBinaryTest(128);
        sobelBinaryTest(64);
        sobelBinaryTest(32);
    }

    private static void sobel(String sourcePath, String targetPath) {
        try {
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getBytes(image);
            //生成新图像的二维数组
            int[][] newImgArrays = EdgeDetectionUtils.sobel(imgArrays);
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            ImageUtils.setIntsForGray(newImage, newImgArrays);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void sobelBinaryTest(int threshold) {
        String sourcePath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena-sobel.jpg";
        String targetPath = "G:\\xiaojie-java-test\\img\\边缘检测\\Lena-sobel-binary-" + threshold + ".jpg";
        ImageService.toBinaryImg(sourcePath, targetPath, threshold);
    }
}

2、EdgeDetectionUtils 类。

package com.zxj.reptile.utils.image;

/**
 * 图像边缘检测
 */
public class EdgeDetectionUtils {
    /*
     * 一阶微分算子:Roberts 、Sobel 、Prewitt
     * G = Math.sqrt(Gx^2 + Gy^2)
     * angle = arctan(Gy / Gx)
     */


    /**
     * 边缘检测--Sobel
     * Gx=f(x+1,y-1)+2f(x+1,y)+f(x+1,y+1)-(f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1))
     * Gy=f(x-1,y+1)+2f(x,y+1)+f(x+1,y+1)-(f(x-1,y-1)+2f(x,y-1)+f(x+1,y-1))
     * Gx=[-1 0  1] , Gy=[-1 -2 -1]
     * ---[-2 0  2]      [ 0  0  0]
     * ---[-1 0  1]      [ 1  2  1]
     */
    public static int[][] sobel(int[][] array) {
        int row = array.length;
        int column = array[0].length;
        int[][] newArray = new int[row][column];
        //注意:x = j = column , y = i = row
        for (int i = 0; i < row; i++) {//图片第几行
            for (int j = 0; j < column; j++) {//图片第几列
                int sum, sumX, sumY;
                if (i > 0 && j > 0 && i < row - 1 && j < column - 1) {
                    //Gx=f(x+1,y-1)+f(x+1,y)+f(x+1,y+1)-(f(x-1,y-1)+f(x-1,y)+f(x-1,y+1))
                    //Gy=f(x-1,y+1)+f(x,y+1)+f(x+1,y+1)-(f(x-1,y-1)+f(x,y-1)+f(x+1,y-1))
                    sumX = array[i - 1][j + 1] + 2 * array[i][j + 1] + array[i + 1][j + 1] -
                            (array[i - 1][j - 1] + 2 * array[i][j - 1] + array[i + 1][j - 1]);
                    sumY = array[i + 1][j - 1] + 2 * array[i + 1][j] + array[i + 1][j + 1] -
                            (array[i - 1][j - 1] + 2 * array[i - 1][j] + array[i - 1][j + 1]);
                    sum = (int) Math.sqrt(sumX * sumX + sumY * sumY);
                    newArray[i][j] = sum > 0xff ? 0xff : sum;
                } else if (i < row - 1 && j < column - 1) {
                    //Gx=f(x+1,y+1)-f(x,y),
                    //Gy=f(x,y+1)-f(x+1,y)
                    sumX = array[i + 1][j + 1] - array[i][j];
                    sumY = array[i + 1][j] - array[i][j + 1];
                    sum = (int) Math.sqrt(sumX * sumX + sumY * sumY);
                    newArray[i][j] = sum > 0xff ? 0xff : sum;
                } else if (j == column - 1) {
                    //最后一列
                    newArray[i][j] = newArray[i][j - 1];
                } else if (i == row - 1) {
                    //最后一行
                    newArray[i][j] = newArray[i - 1][j];
                }
            }
        }
        return ImageUtils.rangeByte(newArray);
    }
}

三、结果

1、原图。

2、生成的结果截图。

3、图片边缘检测的图片。

4、将图片边缘检测的图片二值化,其中阈值分别为:32、64、128。                                                           

 

四、详细代码

详细代码可以查看文章图像边缘检测 Reberts边缘检测的详细代码,因为一样的,就不重复写出了。

2018-03-04 11:47:50 qq_27490767 阅读数 1849
  • Android App性能调优、内存泄露检测

    本课程属于Android的部分,主要讲解Android性能调优的多种方式(如通过Android手机自身的工具,算法优化、严格模式等),以及如何用不同的工具检测出内存泄露点。学员通过本课程的学员,可以达到Android开发的阶段。

    10949 人正在学习 去看看 李宁

介绍两种最简单实用的方法,方法如下:

一、简介

(1)Roberts 算子

   基于 Roberts算子的边缘检测法是通过局部差分算法对图像进行运算处理,进而得到图像边界点的检测方法,其边界点的检测公式如下:


这个公式的意思是,当边缘不存在的时候,图形中边缘内部会全部变为0,只有边缘才会变成1,最终我们得到的图像就是边缘图像。


(2) Sobel 算子 

     基于 Sobel 算子的边缘检测法由包含水平边缘和垂直边缘信息的卷积核组成,其中水平边缘信息的卷积核对该检测法的影响较大。该方法的主要原理是通过卷积算法得到水平边缘和垂直边缘的最大值,将该值作为 Sobel 算子输出,进而实现对图像的边缘检测并提取。

 二、matlab仿真

#读入图象:
a=imread(2.jpg);
subplot(3,1,1);
imshow(a);
#采用Roberts算子
b=edge(rgb2gray(a));
subplot(3,1,2);
imshow(b);
#Sobel算子:
c=edge(rgb2gray(a)); 

subplot(3,1,2);

imshow(c);

效果图如下,可见,边缘被很好的检测了出来




2017-07-08 17:31:56 lindamtd 阅读数 1337
  • Android App性能调优、内存泄露检测

    本课程属于Android的部分,主要讲解Android性能调优的多种方式(如通过Android手机自身的工具,算法优化、严格模式等),以及如何用不同的工具检测出内存泄露点。学员通过本课程的学员,可以达到Android开发的阶段。

    10949 人正在学习 去看看 李宁

最近自己在做一个有关图像处理的小项目,涉及到图像的边缘检测、直线检测、轮廓检测以及角点检测等,本文首先介绍图像的边缘检测,使用的是Canny边缘检测算法,具体代码以及检测效果如下:

1、代码部分:

// Image_Canny.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <cv.h>
#include "highgui.h"
using namespace cv;

int _tmain(int argc, _TCHAR* argv[])
{
	Mat src_img=imread("..\\image_norm\\71253.jpg");
	imshow("src_img",src_img);
	Mat img_canny(src_img.size(),CV_8UC1,Scalar(0));
	//canny detect
	Canny(src_img,img_canny,100,300,3,true);
	imshow("img_canny",img_canny);
	imwrite("..\\post_img\\canny.jpg",img_canny);
	
	cvWaitKey(0);
	
	return 0;
}
2、原图以及边缘检测效果图:

至此,图像的边缘检测已经实现,在此记录下来,也供初学者参考,最近一直在加班写代码调试代码,最大的感触就是:代码因在不断调试中而愈加精致。

2017-10-02 17:27:49 cymy001 阅读数 1088
  • Android App性能调优、内存泄露检测

    本课程属于Android的部分,主要讲解Android性能调优的多种方式(如通过Android手机自身的工具,算法优化、严格模式等),以及如何用不同的工具检测出内存泄露点。学员通过本课程的学员,可以达到Android开发的阶段。

    10949 人正在学习 去看看 李宁

本文内容参考《数字图像处理基础》Wilhelm Burger等著。
边缘:图像中那些沿某一方向局部强度变化显著的位置。局部强度变化越强烈,越能证明这一位置存在边缘。

基于梯度的边缘检测:

将图像矩阵的一行灰度变化看作一个一维函数f(x),则像素变化就是f(x)=dfdx(x)。对于离散函数f(u),用中心差分公式粗略估计点u处的切线斜率

dfdu(u)f(u+1)f(u1)(u+1)(u1)=f(u+1)f(u1)2=(0.500.5)f(u1)f(u)f(u+1)

由上式可见,对原图像像素数组进行边缘检测梯度滤波,就是用线性算子(0.500.5)与对应位置的像素数组做卷积线性滤波。

对图像函数局部梯度的近似是很多经典边缘检测算子的基础,不同边缘检测算子的差异在于:(1.)估算梯度分量的滤波器类型;(2.)将这些梯度分量结合起来的办法。而我们在边缘检测时,关心的主要是:(a.)边缘点的强度;(b.)边缘的方向。

(1.)Prewitt算子(滤波矩阵):

HPx=111000111=111(101)

HPy=101101101=(111)101

经尺度因子作用滤波算子后,对原图像的滤波输出
Dx=16HPxI,Dy=16HPyI

局部边缘强度E(u,v)
E(u,v)=(Dx(u,v))2+(Dy(u,v))2

局部边缘方向角Φ(u,v)
Φ(u,v)=arctan(Dy(u,v)Dx(u,v))

(2.)Sobel算子(滤波矩阵):

HSx=121000121=121(101)

HSy=101202101=(121)101

经尺度因子作用滤波算子后,对原图像的滤波输出
Dx=18HSxI,Dy=18HSyI

局部边缘强度E(u,v)
E(u,v)=(Dx(u,v))2+(Dy(u,v))2

局部边缘方向角Φ(u,v)
Φ(u,v)=arctan(Dy(u,v)Dx(u,v))

(3.)改进的Sobel算子(滤波矩阵):

HSx=13231030003103

HSy=13230310010303

经尺度因子作用滤波算子后,对原图像的滤波输出
Dx=HSxI,Dy=HSyI

局部边缘强度E(u,v)
E(u,v)=(Dx(u,v))2+(Dy(u,v))2

局部边缘方向角Φ(u,v)
Φ(u,v)=arctan(Dy(u,v)Dx(u,v))

(4.)Roberts算子(滤波矩阵):使用两个非常小的2×2滤波器沿图像的对角线方向估算方向梯度

HR1=(0110)

HR2=(1001)

经尺度因子作用滤波算子后,对原图像的滤波输出
Dx=12HR1I,Dy=12HR2I

局部边缘强度E(u,v)
E(u,v)=(Dx(u,v))2+(Dy(u,v))2

局部边缘方向角Φ(u,v)
Φ(u,v)=arctan(Dy(u,v)Dx(u,v))

一个滤波器如果对类似边缘的结构相应越强,那它对方向性就越敏感。方向不敏感的滤波器趋向于对非边缘结构有良好的响应,而最具识别能力的边缘检测滤波器,通常只对一个比较狭小的角度范围内的边缘有相应。

(5.)罗盘算子(滤波矩阵):使用一系列敏感方向范围较窄的滤波器,如下述的8个方向跨距为45o的滤波器。

HS0=121000121HS4=121000121

HS1=210101012HS5=210101012

HS2=101202101HS6=101202101

HS3=012101210HS7=012101210

每个方向的输出
D0=IHS0,D1=IHS1,D2=IHS2,D3=IHS3,D4=D0,D5=D1,D6=D2,D7=D3

(u,v)处的边缘强度
ES(u,v)=max(|D0(u,v)|,|D1(u,v)|,|D2(u,v)|,|D3(u,v)|)

局部的边缘方向
ΦS(u,v)=π4j,j=argmax0i7Di(u,v)

基于一阶导数的边缘检测算子得到的边缘是与灰度过渡范围等宽的,因此边缘无法被精确定位。

基于二阶导数的边缘检测:

函数的二阶导数可以度量局部曲率,边缘通常存在于图像函数的二阶导数的零点位置(过零点处)。此外,由于二阶导数通常会放大图像噪声,所以需要用合适的低通滤波器做预平滑处理。

多尺度边缘检测技术:

边缘并不是仅仅存在于某个固定分辨率或尺度上,而是遍及多种可能的尺度。所以,多尺度边缘检测技术首先检测各种尺度下的边缘,然后在每个图像位置上判断哪一个尺度上的那一条边缘是主要的
(1.)Canny算子:在不同分辨率的图像上使用一系列的相对大尺寸的有向滤波器进行滤波,然后将这些滤波结果融合起来成为一张正常的边缘图。它是一种基于一阶导数的梯度方法,使用二阶导数的过零点精确定位边缘。

2019-11-26 17:12:42 qq_36511401 阅读数 1228
  • Android App性能调优、内存泄露检测

    本课程属于Android的部分,主要讲解Android性能调优的多种方式(如通过Android手机自身的工具,算法优化、严格模式等),以及如何用不同的工具检测出内存泄露点。学员通过本课程的学员,可以达到Android开发的阶段。

    10949 人正在学习 去看看 李宁

底下有详细代码

一、介绍

1、图像检测的原理。

        图像检测的原理是检测相邻的几个点像素值之间的变化率,相对于对函数求导。求点P(x,y)的变换率,可以在点P周围选取一些点,求x方向的距离Gx,再求y方向上的距离Gy。最后变换率G等于Gx平方加上Gy平方的和的平方差,即G=Math.sqrt(Gx^2+Gy^2)。

2、Laplacian算子。

        拉普拉斯算子对噪声敏感。对图像中的阶跃性边缘点定位正确,对噪声十分的敏感,会丢失一部分边缘的方向信息,造成一些不连续的检测边缘。Laplacian 算子是n维欧几里德空间中的一个二阶微分算子。

3、Laplacian算子模版有两个。

(1)V1

        G^2=f(x-1,y)+f(x+1,y)+f(x,y-1)+f(x,y+1)-4f(x,y)
        G^2=[0  1  0]
                [1 -4  1]
                [0  1  0]

(2)V2
        G^2=f(x-1,y-1)+f(x,y-1)+f(x+1,y-1)+f(x-1,y)+f(x+1,y)+f(x-1,y+1)+f(x,y+1)+f(x+1,y+1)-8f(x,y)
        G^2=[1  1  1]
                [1 -8  1]
                [1  1  1]

二、Laplacian模版V1

1、主流程代码。

package com.zxj.reptile.test.image.edge;

import com.zxj.reptile.utils.image.EdgeDetectionUtils;
import com.zxj.reptile.utils.image.ImageService;
import com.zxj.reptile.utils.image.ImageUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

/**
 * 图像边缘检测
 */
public class EdgeDetectionTest {
    public static void main(String[] args) {
        laplacianTest();
    }

    private static void laplacianTest() {
        String path = "G:\\xiaojie-java-test\\img\\边缘检测\\";
        String sourcePath = path + "Lena灰度图.jpg";

        //laplacianV1
        String targetPath1 = path + "Lena-laplacianV1.jpg";
        laplacianV1(sourcePath, targetPath1);
        //二值化
        ImageService.toBinaryImg(targetPath1, path + "Lena-laplacianV1-binary-96.jpg", 96);
        ImageService.toBinaryImg(targetPath1, path + "Lena-laplacianV1-binary-64.jpg", 64);
        ImageService.toBinaryImg(targetPath1, path + "Lena-laplacianV1-binary-32.jpg", 32);
    }

    private static void laplacianV1(String sourcePath, String targetPath) {
        try {
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getImageGray(image);
            //生成新图像的二维数组
            int[][] newImgArrays = EdgeDetectionUtils.laplacianV1(imgArrays);
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            ImageUtils.setImageRgbByByte(newImage, newImgArrays);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2、核心代码。

package com.zxj.reptile.utils.image;

/**
 * 图像边缘检测
 * G = Math.sqrt(Gx^2 + Gy^2)
 * angle = arctan(Gy / Gx)
 */
public class EdgeDetectionUtils {

    /**
     * 边缘检测--Laplacian--v1--噪声敏感
     * G^2=f(x-1,y)+f(x+1,y)+f(x,y-1)+f(x,y+1)-4f(x,y)
     * G^2=[0  1  0]
     * ----[1 -4  1]
     * ----[0  1  0]
     */
    public static int[][] laplacianV1(int[][] array) {
        int row = array.length;
        int column = array[0].length;
        int[][] newArray = new int[row][column];
        //注意:x = j = column , y = i = row
        for (int i = 1; i < row - 1; i++) {//图片第几行
            for (int j = 1; j < column - 1; j++) {//图片第几列
                //G^2=f(x-1,y)+f(x+1,y)+f(x,y-1)+f(x,y+1)-4f(x,y)
                int sum = array[i][j - 1] + array[i][j + 1] + array[i - 1][j] + array[i + 1][j] - 4 * array[i][j];
                newArray[i][j] = (int) Math.round(Math.sqrt(sum));
            }
        }
        return ImageUtils.rangeToByte(newArray);
    }
}

3、结果。

(1)原图和结果。

 

(2)结果二值化,阈值分别为32、64、96。

(3)截图。

三、Laplacian模版V2

1、主流程代码。

package com.zxj.reptile.test.image.edge;

import com.zxj.reptile.utils.image.EdgeDetectionUtils;
import com.zxj.reptile.utils.image.ImageService;
import com.zxj.reptile.utils.image.ImageUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

/**
 * 图像边缘检测
 */
public class EdgeDetectionTest {
    public static void main(String[] args) {
        laplacianTest();
    }

    private static void laplacianTest() {
        String path = "G:\\xiaojie-java-test\\img\\边缘检测\\";
        String sourcePath = path + "Lena灰度图.jpg";

        //laplacianV2
        String targetPath2 = path + "Lena-laplacianV2.jpg";
        laplacianV2(sourcePath, targetPath2);
        //二值化
        ImageService.toBinaryImg(targetPath2, path + "Lena-laplacianV2-binary-96.jpg", 96);
        ImageService.toBinaryImg(targetPath2, path + "Lena-laplacianV2-binary-64.jpg", 64);
        ImageService.toBinaryImg(targetPath2, path + "Lena-laplacianV2-binary-32.jpg", 32);
    }

    private static void laplacianV2(String sourcePath, String targetPath) {
        try {
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getImageGray(image);
            //生成新图像的二维数组
            int[][] newImgArrays = EdgeDetectionUtils.laplacianV2(imgArrays);
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            ImageUtils.setImageRgbByByte(newImage, newImgArrays);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2、核心代码。

package com.zxj.reptile.utils.image;

/**
 * 图像边缘检测
 * G = Math.sqrt(Gx^2 + Gy^2)
 * angle = arctan(Gy / Gx)
 */
public class EdgeDetectionUtils {
    /**
     * 边缘检测--Laplacian--v2--噪声敏感
     * G^2=f(x-1,y-1)+f(x,y-1)+f(x+1,y-1)+f(x-1,y)+f(x+1,y)+f(x-1,y+1)+f(x,y+1)+f(x+1,y+1)-8f(x,y)
     * G^2=[1  1  1]
     * ----[1 -8  1]
     * ----[1  1  1]
     */
    public static int[][] laplacianV2(int[][] array) {
        int row = array.length;
        int column = array[0].length;
        int[][] newArray = new int[row][column];
        //注意:x = j = column , y = i = row
        for (int i = 1; i < row - 1; i++) {//图片第几行
            for (int j = 1; j < column - 1; j++) {//图片第几列
                //G^2=f(x-1,y-1)+f(x,y-1)+f(x+1,y-1)+f(x-1,y)-8f(x,y)+f(x+1,y)+f(x-1,y+1)+f(x,y+1)+f(x+1,y+1)
                int sum = array[i - 1][j - 1] + array[i - 1][j] + array[i - 1][j + 1] +
                        array[i][j - 1] - 8 * array[i][j] + array[i][j + 1] +
                        array[i + 1][j - 1] + array[i + 1][j] + array[i + 1][j + 1];
                newArray[i][j] = (int) Math.round(Math.sqrt(sum));
            }
        }
        return ImageUtils.rangeToByte(newArray);
    }
}

3、结果。

(1)原图和结果。

(2)结果二值化,阈值分别为32、64、96。

(3)截图。

四、详细代码

1、FilterUtils.java。

package com.zxj.reptile.utils.image;

import com.zxj.reptile.utils.algorithm.SortUtils;

public class FilterUtils {
    /**
     * 中值滤波
     *
     * @param imgArrays    图像二维数组
     * @param filterLength 过滤的长度(阈值)
     */
    public static int[][] getMiddleFilter(int[][] imgArrays, int filterLength) {
        final int imgHeight = imgArrays.length;
        final int imgWidth = imgArrays[0].length;
        int[][] newImgArrays = new int[imgHeight][imgWidth];
        //模版半径
        final int filterRadius = (filterLength - 1) / 2;
        final int filterSize = filterLength * filterLength;
        //获取数据
        for (int h = 0; h < imgHeight; h++) {//图片第几行
            for (int w = 0; w < imgWidth; w++) {//图片第几列
                int count = 0;
                int[] templateArray = new int[filterSize];
                for (int templateH = -filterRadius; templateH <= filterRadius; templateH++) {//模版第几行
                    int rowIndex = h + templateH;
                    if (rowIndex < 0 || rowIndex > imgHeight - 1) {
                        continue;
                    }
                    for (int templateW = -filterRadius; templateW <= filterRadius; templateW++) {//模版第几列
                        int columnIndex = w + templateW;
                        if (columnIndex < 0 || columnIndex > imgWidth - 1) {
                            continue;
                        }
                        templateArray[count++] = imgArrays[rowIndex][columnIndex];
                    }
                }
                //
                int[] newTemplateArray;
                if (count != templateArray.length) {
                    newTemplateArray = new int[count];
                    for (int i = 0; i < count; i++) {
                        newTemplateArray[i] = templateArray[i];
                    }
                    SortUtils.countSort(newTemplateArray);//计数排序
                    newImgArrays[h][w] = newTemplateArray[count / 2];
                } else {
                    SortUtils.countSort(templateArray);//计数排序
                    newImgArrays[h][w] = templateArray[filterRadius];
                }
            }
        }
        return newImgArrays;
    }

    /**
     * 均值滤波
     *
     * @param imgArrays    图像二维数组
     * @param filterLength 过滤的长度(阈值)
     */
    public static int[][] getAverageFilter(int[][] imgArrays, int filterLength) {
        final int imgHeight = imgArrays.length;
        final int imgWidth = imgArrays[0].length;
        int[][] newImgArrays = new int[imgHeight][imgWidth];
        //模版半径
        final int filterRadius = (filterLength - 1) / 2;
        //获取数据
        for (int h = 0; h < imgHeight; h++) {//图片第几行
            for (int w = 0; w < imgWidth; w++) {//图片第几列
                int count = 0;
                int sum = 0;
                for (int templateH = -filterRadius; templateH <= filterRadius; templateH++) {//模版第几行
                    int rowIndex = h + templateH;
                    if (rowIndex < 0 || rowIndex > imgHeight - 1) {
                        continue;
                    }
                    for (int templateW = -filterRadius; templateW < filterRadius; templateW++) {//模版第几列
                        int columnIndex = w + templateW;
                        if (columnIndex < 0 || columnIndex > imgWidth - 1) {
                            continue;
                        }
                        sum += imgArrays[rowIndex][columnIndex];
                        count++;
                    }
                }
                newImgArrays[h][w] = sum / count;
            }
        }
        return newImgArrays;
    }

    /**
     * 获取高斯滤波模版的二维数组
     *
     * @param length 模版长度,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     * @param sigma  模版标准差,length=6sigma(%99.74), length=4sigma(95%), length=2sigma(68%)
     */
    public static double[][] getGaussTemplate(int length, double sigma) {
        double[][] gaussTemplate = new double[length][length];    // 用于存储结果
        int centerIndex = (length - 1) / 2;//模版的中心点
        double variance = sigma * sigma;//方差
        double sum = 0;
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < length; ++j) {
                int xLength = j - centerIndex;//x上的距离
                int yLength = i - centerIndex;//y上的距离
                double e = Math.exp(-(xLength * xLength + yLength * yLength) / (2 * variance));
                gaussTemplate[i][j] = e / (2 * Math.PI * variance);
                sum += gaussTemplate[i][j];
            }
        }
        //占得比重
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < length; ++j) {
                gaussTemplate[i][j] = gaussTemplate[i][j] / sum;
            }
        }
//        //打印模版
//        System.out.println(String.format("生成大小为%d,标准差为%.3f的二维高斯模版:", length, sigma));
//        for (double[] doubles : gaussTemplate) {
//            for (int j = 0; j < gaussTemplate.length; j++) {
//                System.out.print(String.format("%8.3f", doubles[j]));
//            }
//            System.out.println();
//        }
        return gaussTemplate;
    }

    /**
     * 高斯滤波
     *
     * @param imgArrays     图像二维数组
     * @param gaussTemplate 高斯滤波模版的二维数组
     */
    public static int[][] getGaussFilter(int[][] imgArrays, double[][] gaussTemplate) {
        final int imgHeight = imgArrays.length;
        final int imgWidth = imgArrays[0].length;
        int[][] newImgArrays = new int[imgHeight][imgWidth];
        //模版长度和半径
        final int filterLength = gaussTemplate.length;
        final int filterRadius = (filterLength - 1) / 2;
        //高斯过滤
        for (int h = 0; h < imgHeight; h++) {//图片第几行
            for (int w = 0; w < imgWidth; w++) {//图片第几列
                double weightTotal = 0;
                double sum = 0;
                for (int templateH = -filterRadius; templateH <= filterRadius; templateH++) {//模版第几行
                    int rowIndex = h + templateH;
                    if (rowIndex < 0 || rowIndex > imgHeight - 1) {
                        continue;
                    }
                    for (int templateW = -filterRadius; templateW < filterRadius; templateW++) {//模版第几列
                        int columnIndex = w + templateW;
                        if (columnIndex < 0 || columnIndex > imgWidth - 1) {
                            continue;
                        }
                        double weight = gaussTemplate[templateH + filterRadius][templateW + filterRadius];
                        sum += (imgArrays[rowIndex][columnIndex] * weight);
                        weightTotal += weight;
                    }
                }
                newImgArrays[h][w] = (int) (sum / weightTotal);
            }
        }
        return newImgArrays;
    }
}

2、ImageService.java。

package com.zxj.reptile.utils.image;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

public class ImageService {
    /**
     * 图片灰度化的方法
     *
     * @param sourcePath 源图片路径
     * @param targetPath 目标图片路径
     * @param grayType   灰度化方法
     */
    public static void toGrayImg(String sourcePath, String targetPath, int grayType) {
        try {
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getImageRgb(image);
            //生成新图像的二维数组
            int[][] newImgArrays = ImageUtils.grayProcess(imgArrays, grayType);//灰度化
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            ImageUtils.setImageRgbByByte(newImage, newImgArrays);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成不同rgb通道图片的方法
     *
     * @param sourcePath   源图片路径
     * @param targetPath   rgb通道图片路径
     * @param channelColor r、g、b颜色通道
     */
    public static void toChannelImg(String sourcePath, String targetPath, int channelColor) {
        try {
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getImageRgb(image);
            //生成新图像的二维数组
            int[][] newImgArrays = ImageUtils.channelProcess(imgArrays, channelColor);
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
            ImageUtils.setImageRgb(newImage, newImgArrays);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 二值化
     *
     * @param sourcePath 源图片路径
     * @param targetPath 目标二值图片路径
     * @param threshold  阈值
     */
    public static void toBinaryImg(String sourcePath, String targetPath, int threshold) {
        try {
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getImageGray(image);
            //生成新图像的二维数组
            int[][] newImgArrays = ImageUtils.binaryProcess(imgArrays, threshold);//二值化
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
            ImageUtils.setImageBytes(newImage, newImgArrays);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3、ImageUtils.java。

package com.zxj.reptile.utils.image;

import java.awt.image.BufferedImage;

/**
 * 要用int,不能使用byte,因为byte最大值为128
 */
public class ImageUtils {
    /**
     * 灰度处理的方法
     */
    public static final byte Gray_Type_Min = 1;//最大值法
    public static final byte Gray_Type_Max = 2;//最小值法
    public static final byte Gray_Type_Average = 3;//平均值法
    public static final byte Gray_Type_Weight = 4;//加权法
    public static final byte Gray_Type_Red = 5;//红色值法
    public static final byte Gray_Type_Green = 6;//绿色值法
    public static final byte Gray_Type_Blue = 7;//蓝色值法
    public static final byte Gray_Type_Default = Gray_Type_Weight;//默认加权法

    /**
     * 不同颜色通道的图片
     */
    public static final byte Channel_Color_Red = 1;
    public static final byte Channel_Color_Green = 2;
    public static final byte Channel_Color_Blue = 3;

    /**
     * 灰度化处理,彩色int[][] 转 灰度byte[][]
     *
     * @param imgArrays 图像二维数组
     * @param grayType  灰度化方法
     */
    public static int[][] grayProcess(int[][] imgArrays, int grayType) throws Exception {
        int[][] newImgArrays = new int[imgArrays.length][imgArrays[0].length];
        for (int h = 0; h < imgArrays.length; h++)
            for (int w = 0; w < imgArrays[0].length; w++)
                newImgArrays[h][w] = getImageGray(getImageRgb(imgArrays[h][w]), grayType);
        return newImgArrays;
    }

    /**
     * 颜色通道处理,彩色int[][] 转 彩色int[][]
     *
     * @param imgArrays    图像二维数组
     * @param channelColor 不同颜色通道
     */
    public static int[][] channelProcess(int[][] imgArrays, int channelColor) {
        int[][] newImgArrays = new int[imgArrays.length][imgArrays[0].length];
        for (int h = 0; h < imgArrays.length; h++) {
            for (int w = 0; w < imgArrays[0].length; w++) {
                final int pixel = imgArrays[h][w];
                if (channelColor == Channel_Color_Red) {
                    newImgArrays[h][w] = pixel & 0xff0000;
                } else if (channelColor == Channel_Color_Green) {
                    newImgArrays[h][w] = pixel & 0x00ff00;
                } else if (channelColor == Channel_Color_Blue) {
                    newImgArrays[h][w] = pixel & 0x0000ff;
                }
            }
        }
        return newImgArrays;
    }

    /**
     * 二值化处理,灰度byte[][] 转 二值byte[][]
     *
     * @param imgArrays 灰度 int[][]
     * @param threshold 阈值
     */
    public static int[][] binaryProcess(int[][] imgArrays, int threshold) {
        int[][] newImgArrays = new int[imgArrays.length][imgArrays[0].length];
        for (int h = 0; h < imgArrays.length; h++)
            for (int w = 0; w < imgArrays[0].length; w++) {
                newImgArrays[h][w] = (imgArrays[h][w] < threshold ? 0 : 0xff);
            }
        return newImgArrays;
    }

    /**
     * 根据像素,返回r、g、b 的 byte[]
     *
     * @param pixel 像素值
     */
    private static int[] getImageRgb(int pixel) {
        int[] rgb = new int[3];
        rgb[0] = ((pixel >> 16) & 0xff);
        rgb[1] = ((pixel >> 8) & 0xff);
        rgb[2] = (pixel & 0xff);
        return rgb;
    }

    /**
     * 获取像素值
     *
     * @param pixel 像素值
     */
    public static long getPixel(int pixel) {
        return (pixel & 0xff) + (pixel & 0xff00) + (pixel & 0xff0000);
    }

    /**
     * 获取像素值
     *
     * @param rgb r、g、b 的 byte[]
     */
    public static long getPixel(int[] rgb) {
        return (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
    }

    /**
     * 根据r、g、b 的 byte[],返回灰度值
     *
     * @param rgb      r、g、b颜色通道的值
     * @param grayType 不同灰度处理的方法
     */
    private static int getImageGray(int[] rgb, int grayType) throws Exception {
        if (grayType == Gray_Type_Average) {
            return ((rgb[0] + rgb[1] + rgb[2]) / 3);   //rgb之和除以3
        } else if (grayType == Gray_Type_Weight) {
            return (int) (0.3 * rgb[0] + 0.59 * rgb[1] + 0.11 * rgb[2]);
        } else if (grayType == Gray_Type_Red) {
            return rgb[0];//取红色值
        } else if (grayType == Gray_Type_Green) {
            return rgb[1];//取绿色值
        } else if (grayType == Gray_Type_Blue) {
            return rgb[2];//取蓝色值
        }
        //比较三个数的大小
        int gray = rgb[0];
        for (int i = 1; i < rgb.length; i++) {
            if (grayType == Gray_Type_Min) {
                if (gray > rgb[i]) {
                    gray = rgb[i];//取最小值
                }
            } else if (grayType == Gray_Type_Max) {
                if (gray < rgb[i]) {
                    gray = rgb[i];//取最大值
                }
            } else {
                throw new Exception("grayType出错");
            }
        }
        return gray;
    }

    /**
     * 获取图像像素 byte[][] rgb值
     *
     * @param image BufferedImage图像对象
     */
    public static int[][] getImageRgb(BufferedImage image) {
        int[][] imgArrays = new int[image.getHeight()][image.getWidth()];
        for (int i = 0; i < image.getHeight(); i++)
            for (int j = 0; j < image.getWidth(); j++)
                imgArrays[i][j] = image.getRGB(j, i);
        return imgArrays;
    }

    /**
     * 获取图像像素 byte[][] 灰度值
     *
     * @param image BufferedImage图像对象
     */
    public static int[][] getImageGray(BufferedImage image) throws Exception {
        return grayProcess(getImageRgb(image), Gray_Type_Default);
    }

    /**
     * 获取图像像素 byte[][] 二值
     *
     * @param image BufferedImage图像对象
     */
    public static int[][] getImageBinary(BufferedImage image) throws Exception {
        return binaryProcess(grayProcess(getImageRgb(image), Gray_Type_Default), 0xff / 2);
    }

    /**
     * 图像像素填充 byte[][]
     *
     * @param image     BufferedImage图像对象
     * @param imgArrays 二维像素
     */
    public static void setImageBytes(BufferedImage image, int[][] imgArrays) {
        for (int i = 0; i < image.getHeight(); i++)
            for (int j = 0; j < image.getWidth(); j++)
                image.setRGB(j, i, (byte) imgArrays[i][j]);
    }

    /**
     * 图像像素填充 byte[][]
     *
     * @param image     BufferedImage图像对象
     * @param imgArrays 二维像素
     */
    public static void setImageBytes(BufferedImage image, byte[][] imgArrays) {
        for (int i = 0; i < image.getHeight(); i++)
            for (int j = 0; j < image.getWidth(); j++)
                image.setRGB(j, i, imgArrays[i][j]);
    }

    /**
     * 图像像素填充 int[][]
     *
     * @param image     BufferedImage图像对象
     * @param imgArrays 二维像素
     */
    public static void setImageRgb(BufferedImage image, int[][] imgArrays) {
        for (int i = 0; i < image.getHeight(); i++)
            for (int j = 0; j < image.getWidth(); j++)
                image.setRGB(j, i, imgArrays[i][j]);
    }

    /**
     * 图像像素填充 将 byte[][] 变为 int[][] 进行填充
     *
     * @param image     BufferedImage图像对象
     * @param imgArrays 二维像素
     */
    public static void setImageRgbByByte(BufferedImage image, int[][] imgArrays) {
        for (int i = 0; i < image.getHeight(); i++)
            for (int j = 0; j < image.getWidth(); j++)
                image.setRGB(j, i, imgArrays[i][j] + (imgArrays[i][j] << 8) + (imgArrays[i][j] << 16));
    }

    /**
     * @param arrays 将数组的值域分布到0--0xff之间
     */
    public static int[][] rangeToByte(int[][] arrays) {
        int max = arrays[0][0], min = arrays[0][0];
        for (int[] array : arrays) {
            for (int value : array) {
                if (value > max) {
                    max = value;
                } else if (value < min) {
                    min = value;
                }
            }
        }
        //
        int[][] newArrays = new int[arrays.length][];
        int range = max - min + 1;
        double multiply = (0xff + 1.0) / range;
        for (int i = 0; i < arrays.length; i++) {
            int[] array = arrays[i];
            int[] newArray = new int[array.length];
            for (int j = 0; j < array.length; j++) {
                int value = (int) Math.round((array[j] - min) * multiply);
                newArray[j] = value > 0xff ? 0xff : value;
            }
            newArrays[i] = newArray;
        }
        return newArrays;
    }
}

边缘检测

阅读数 464

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