Java获取彩色图像中的主色彩的实例代码

本文讲述了Java获取彩色图像中的主色彩的实例代码。分享给大家供大家参考,具体如下:

一:基本思路

对于一张RGB色彩空间的彩色图像,很多时间我们想通过程序获得该图像有几种主要的色彩,但是对一般图像来说,在色彩交界处都是通过像素混合来实现自然过渡,所以直接扫描图像的像素值,得到的不同颜色值可能多达上百中,而实际上图像可能只有3~4种的主要色彩,如何去掉那些混合颜色,准确提取出来这3~4中的主色彩,根据一般图像的特征,图像在不同色彩的边界处混合不同的颜色值,此可以视为图像的边缘特性之一,因此可以根据简单的边缘梯度算法实现这些混合像素的提取得到输出的像素值数组,然后扫描每个像素值,寻找指定半径参数R周围的像素,发现为零,而且距离中心像素最近的像素点的值做为中心像素的像素值,扫描结束以后输出像素数组,然后对数组线性扫描,即可得到图片的主要色彩RGB值。

二:实现步骤
1.      输入图像数组,对彩色图像灰度化;
2.      对灰度化以后的图像,计算图像梯度,这里使用sobol算子;
3.      对得到每一个非零像素点实现半径为R的范围内的扫描,找出与之最相近的为零的原像素值;
4.      对得到数组进行简单的扫描,得到主色彩。

其中参数R是要根据不同应用场景,找到最合适的值。理论上图像越大,R的取值也应该越大,否则算法会失准。

三:原图及运行效果

原图

算法运行之后提取到四种主要色彩

四:算法实现源代码

public static BufferedImage removeBlendPixels(BufferedImage image, int raidus) {
  int width = image.getWidth();
  int height = image.getHeight();
  int[] pixels = new int[width * height];
  getRGB(image, 0, 0, width, height, pixels);
  // 创建处理结果
  BufferedImage resultImg = createCompatibleDestImage(image, null);
  setRGB(resultImg, 0, 0, width, height, pixels);
  // 灰度化与梯度求取
  byte[] grayData = getGrayData(pixels, width, height);
  byte[] binaryData = getGrident(grayData, width, height);
  int index = 0;
  for (int row = 1; row < height - 1; row++) {
   for (int col = 1; col < width - 1; col++) {
    index = row * width + col;
    int pixel = (binaryData[index] & 0xff);
    if (pixel > 0) {
     // 半径扫描操作
     int mindis = Integer.MAX_VALUE;
     int minrow = -1;
     int mincol = -1;
     int nr = 0;
     int nc = 0;
     int index2 = 0;
     for (int subrow = -raidus; subrow <= raidus; subrow++) {
      nr = row + subrow;
      if (nr < 0 || nr >= height) {
       continue;
      }
      for (int subcol = -raidus; subcol <= raidus; subcol++) {
       nc = col + subcol;
       if (nc < 0 || nc >= width) {
        continue;
       }
       index2 = nr * width + nc;
       int value = (binaryData[index2] & 0xff);
       if (value == 0) {
        int distance = distanceColor(image.getRGB(nc, nr), image.getRGB(col, row));
        if (distance < mindis) {
         mindis = distance;
         minrow = nr;
         mincol = nc;
        }
       }
      }
     }
     resultImg.setRGB(col, row, image.getRGB(mincol, minrow));
    }
   }
  }
  return resultImg;
 }
 public static int distanceColor(int rgb, int rgb2) {
  // Color one
  int r1 = (rgb >> 16) & 0xff;
  int g1 = (rgb >> 8) & 0xff;
  int b1 = rgb & 0xff;
  // Color two
  int r2 = (rgb2 >> 16) & 0xff;
  int g2 = (rgb2 >> 8) & 0xff;
  int b2 = rgb2 & 0xff;
  // distance
  int rr = r1 - r2;
  int gg = g1 - g2;
  int bb = b1 - b2;
  int sum = (int) Math.sqrt(rr * rr + gg * gg + bb * bb);
  return sum;
 }
 public static byte[] getGrayData(int[] inPixels, int width, int height) {
  // 图像灰度化
  byte[] outPixels = new byte[width * height];
  int index = 0;
  for (int row = 0; row < height; row++) {
   int tr = 0, tg = 0, tb = 0;
   for (int col = 0; col < width; col++) {
    index = row * width + col;
    tr = (inPixels[index] >> 16) & 0xff;
    tg = (inPixels[index] >> 8) & 0xff;
    tb = inPixels[index] & 0xff;
    int gray = (int) (0.299 * tr + 0.587 * tg + 0.114 * tb);
    outPixels[index] = (byte) (gray & 0xff);
   }
  }
  return outPixels;
 }
 public static byte[] getGrident(byte[] inPixels, int width, int height) {
  byte[] outPixels = new byte[width * height];
  int index = 0;
  for (int row = 0; row < height; row++) {
   int tr = 0;
   for (int col = 0; col < width; col++) {
    if (row == 0 || col == 0 || (row == height - 1) || (col == width - 1)) {
     index = row * width + col;
     outPixels[index] = (byte) (0x00);
     continue;
    }
    int xg = 0, yg = 0;
    for (int sr = -1; sr <= 1; sr++) {
     for (int sc = -1; sc <= 1; sc++) {
      int nrow = row + sr;
      int ncol = col + sc;
      if (nrow < 0 || nrow >= height) {
       nrow = 0;
      }
      if (ncol < 0 || ncol >= width) {
       ncol = 0;
      }
      index = nrow * width + ncol;
      tr = (inPixels[index] & 0xff);
      xg += X_SOBEL[sr + 1][sc + 1] * tr;
      yg += Y_SOBEL[sr + 1][sc + 1] * tr;
     }
    }
    index = row * width + col;
    int g = (int) Math.sqrt(xg * xg + yg * yg);
    outPixels[index] = (byte) (clamp(g) & 0xff);
   }
  }
  return outPixels;
 }

需要定义的常量值如下:

public static final int[][] X_SOBEL = new int[][] { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
public static final int[][] Y_SOBEL = new int[][] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
public static final int BLOCK_PIXEL_RADIUS = 5; 

梯度求取使用是sobol算子,对处理以后的BufferedImage对象扫描获取主色彩的代码如下:

int width = result.getWidth();
int height = result.getHeight();
Map<Integer, Integer> colorIndexMap = new HashMap<Integer, Integer>();
for (int row = 0; row < height; row++) {
 for (int col = 0; col < width; col++) {
  int pixelValue = result.getRGB(col, row);
  if (!colorIndexMap.containsKey(pixelValue)) {
   colorIndexMap.put(pixelValue, pixelValue);
  }
 }
}
// now scan pixel value
// return result
System.out.println("number of color = " + colorIndexMap.size());
return colorIndexMap.keySet().toArray(new Integer[0]);

测试代码如下:

public static void main(String[] args) {
 File file = new File("D:\\gloomyfish\\bigmonkey.png");
 File resultFile = new File("D:\\gloomyfish\\result.png");
 try {
  BufferedImage image = ImageIO.read(file);
  BufferedImage result = removeBlendPixels(image, BLOCK_PIXEL_RADIUS);
  ImageIO.write(result, "png", resultFile);
  Integer[] colors = extractColors(result);
  System.out.println("total colors : " + colors.length);
 } catch (IOException e) {
  e.printStackTrace();
 }
} 

注意:主要的关键在于对待处理图像输入正确大小的半径,这个半径大小跟图像实际大小相关,而且算法可以近一步优化成不依赖半径参数的版本,知道找到等于零的像素为止。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • java数字图像处理基础使用imageio写图像文件示例
  • Java图像处理工具类
  • 详解Java如何实现图像灰度化
  • 使用Java进行图像处理的一些基础操作
  • 使用Java设置字型和颜色的方法详解
  • java使用颜色选择器示例分享
  • Javacript实现颜色梯度变化和渐变的效果代码
(0)

相关推荐

  • java数字图像处理基础使用imageio写图像文件示例

    一个BufferedImage的像素数据储存在Raster中,ColorModel里面储存颜色空间,类型等信息,当前Java只支持一下三种图像格式- JPG,PNG,GIF,如何向让Java支持其它格式,首先要 完成Java中的图像读写接口,然后打成jar,加上启动参数- Xbootclasspath/pnewimageformatIO.jar即可. Java中如何读写一个图像文件,使用ImageIO对象即可.读图像文件的代码如下: 复制代码 代码如下: File file = new File

  • 使用Java进行图像处理的一些基础操作

    图像是由一组像素构成,用二进制形式保存的图片.java语言支持GIF.JPEG和BMP这3种主要图像文件格式.java语言的图像处理功能被封装在Image类中. 图像载入和输出 在java程序中,图像也是对象,所以载入图像时,先要声明Image对象,然后,利用getImage()方法把Image对象与图像文件联系起来.载入图像文件的方法有两个: Image getImage(URL url),url指明图像所在位置和文件名. Image getImage(URL url,String name)

  • 详解Java如何实现图像灰度化

    24位彩色图与8位灰度图 首先要先介绍一下24位彩色图像,在一个24位彩色图像中,每个像素由三个字节表示,通常表示为RGB.通常,许多24位彩色图像存储为32位图像,每个像素多余的字节存储为一个alpha值,表现有特殊影响的信息[1]. 在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值.亮度值),灰度范围为0-255[2].这样就得到一幅图片的灰度图. 几种灰度化的方法 1.分量法:使用RGB三个分量中

  • java使用颜色选择器示例分享

    复制代码 代码如下: package com.liuxing.test;import java.awt.Color;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JColorChooser;import javax.swing.JFrame;import javax.swing.JLabel;import ja

  • Javacript实现颜色梯度变化和渐变的效果代码

    对于本站的导航栏,想做点什么.所以,选择了用js对导航栏的颜色做了梯度的变化处理. 起初,觉得用opacity属性(透明度)来改变颜色的梯度变化.不过,这样会出现一个问题. 每一个导航标签用的是[li],当鼠标浮动到标签上时,通过onmouseover()立即改变[li]的className,并用setInterval()来使其opacity(透明度)由0变到1.不过,当鼠标离开时,对于[li]标签的颜色恢复的处理貌似麻烦了许多.所以,很快就放弃了这个做法,换种思路. 到百度上一搜,看到了一篇很

  • 使用Java设置字型和颜色的方法详解

    Java绘图中,显示文字的方法主要有三种: (1)drawString(String str,int x,int y):在指定的位置显示字符串. (2)drawChars(char data[],int offset,int length, int x, int y):在指定的位置显示字符数组中的文字,从字符数组的offset位置开始,最多显示length个字符. (3)drawBytes(byte data[],int offset,int length,int x,int y), 在指定的位

  • Java图像处理工具类

    本工具类的功能:缩放图像.切割图像.图像类型转换.彩色转黑白.文字水印.图片水印等 复制代码 代码如下: package net.kitbox.util; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Re

  • Java获取彩色图像中的主色彩的实例代码

    本文讲述了Java获取彩色图像中的主色彩的实例代码.分享给大家供大家参考,具体如下: 一:基本思路 对于一张RGB色彩空间的彩色图像,很多时间我们想通过程序获得该图像有几种主要的色彩,但是对一般图像来说,在色彩交界处都是通过像素混合来实现自然过渡,所以直接扫描图像的像素值,得到的不同颜色值可能多达上百中,而实际上图像可能只有3-4种的主要色彩,如何去掉那些混合颜色,准确提取出来这3-4中的主色彩,根据一般图像的特征,图像在不同色彩的边界处混合不同的颜色值,此可以视为图像的边缘特性之一,因此可以根

  • java 获取对象中为null的字段实例代码

    下面一段简单的代码给大家分享java 获取对象中为null的字段,具体代码如下所述: private static String[] getNullPropertyNames(Object source) { final BeanWrapper src = new BeanWrapperImpl(source); java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); Set<String> emptyNames

  • java使用FFmpeg合成视频和音频并获取视频中的音频等操作(实例代码详解)

    FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序. ffmpeg命令参数如下: 通用选项 -L license -h 帮助 -fromats 显示可用的格式,编解码的,协议的... -f fmt 强迫采用格式fmt -I filename 输入文件 -y 覆盖输出文件 -t duration 设置纪录时间 hh:mm:ss[.xxx]格式的记录时间也支持 -ss position 搜索到指定的时间 [-]hh:mm:ss[.xxx]的格式也支持 -title

  • java 获取request中的请求参数代码详解

    1.get 和 post请求方式 (1)request.getParameterNames(); 获取所有参数key后.遍历request.getParameter(key)获取value (2)request.getParameterMap() .直接包含参数key和value值,简单方便 Map<String, String[]>maps = request.getParameterMap(); for (Map.Entry<String, String[]> entry :

  • java获取json中的全部键值对实例

    如下所示: package com.unionx.wanxue; import java.util.Map; import java.util.Map.Entry; import net.sf.json.JSONObject; /** * 利用jsonObject转map,获取json中的全部键值对 * 在循环中添加条件,也可以获取到特定的键值对 * 注意导包 */ public class test { @SuppressWarnings("unchecked") public st

  • Java 获取Word中所有的插入和删除修订的方法

    目录 ​​引入Jar​​ ​​方法1​​ ​​方法2​​ ​​获取插入.删除的修订​​ 在 Word 文档中启用跟踪更改功能后,会记录文档中的所有编辑行为,例如插入.删除.替换和格式更改.对插入或删除的内容,可通过本文中介绍的方法来获取. ​​引入Jar​​ ​​方法1​​ 手动引入:将Free Spire.Doc for Java下载到本地,解压,找到lib文件夹下的Spire.Doc.jar文件.在IDEA中打开如下界面,将本地路径中的jar文件引入Java程序:​ ​​方法2​​ 通过Ma

  • Java获取Excel中图片所在的行和列坐标位置

    目录 前言 获取图片所在行.列位置 前言 本文以Java代码示例展示如何来获取Excel工作表中图片的坐标位置.这里的坐标位置是指图片左上角顶点所在的单元格行和列位置,横坐标即顶点所在的第几列.纵坐标即顶点所在的第几行.下面是获取图片位置的详细方法及步骤. 程序环境: 按照如下方法来引用Spire.Xls.jar 版本:5.1.0 方法1:将Free Spire.XLS for Java​包下载到本地,解压,找到lib文件夹下的Spire.Xls.jar文件.然后在IDEA中打开“Project

  • Java编程数组中最大子矩阵简便解法实现代码

    本文研究的主要是Java编程数组中最大子矩阵的相关内容,具体介绍如下. 遇到一个好人,可以改变一生:遇到一本好书,又何尝不是呢? 最近在翻阅 左程云先生的<程序员代码面试指南–IT名企算法与数据结构题目最优解>时就非常的有感悟.建议有这方面爱好的博友,也去观摩观摩. 书中讲解的基于栈的数组的最大矩阵的算法很经典,但是博主能力有限,没能彻底的领悟该算法的精髓,但是根据这个思想,博主想出了一种简易的应对该类问题的算法,现概述如下. 核心思想 先来看一张图吧,我们就可以大致的理解了. 如图,每一个轮

  • 列举java语言中反射的常用方法及实例代码

    Java反射机制 一.什么是反射机制  简单的来说,反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,     那么就可以通过反射机制来获得类的所有信息. 二.哪里用到反射机制  有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码,     Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成     驱动对象实例,并不知道

  • java从字符串中提取数字的简单实例

    随便给你一个含有数字的字符串,比如: String s="eert343dfg56756dtry66fggg89dfgf"; 那我们如何把其中的数字提取出来呢?大致有以下几种方法,正则表达式,集合类,还有就是String类提供的方法. 1 String类提供的方法: package 测试练习; import Java.util.*; public class get_StringNum { /** *2016.10.25 */ public static void main(Strin

随机推荐