Java獲取彩色圖像中的主色彩的實例代碼
本文講述了Java獲取彩色圖像中的主色彩的實例代碼。分享給大家供大家參考,具體如下:
一:基本思路
對于一張RGB色彩空間的彩色圖像,很多時間我們想通過程序獲得該圖像有幾種主要的色彩,但是對一般圖像來說,在色彩交界處都是通過像素混合來實現(xiàn)自然過渡,所以直接掃描圖像的像素值,得到的不同顏色值可能多達上百中,而實際上圖像可能只有3~4種的主要色彩,如何去掉那些混合顏色,準確提取出來這3~4中的主色彩,根據(jù)一般圖像的特征,圖像在不同色彩的邊界處混合不同的顏色值,此可以視為圖像的邊緣特性之一,因此可以根據(jù)簡單的邊緣梯度算法實現(xiàn)這些混合像素的提取得到輸出的像素值數(shù)組,然后掃描每個像素值,尋找指定半徑參數(shù)R周圍的像素,發(fā)現(xiàn)為零,而且距離中心像素最近的像素點的值做為中心像素的像素值,掃描結(jié)束以后輸出像素數(shù)組,然后對數(shù)組線性掃描,即可得到圖片的主要色彩RGB值。
二:實現(xiàn)步驟
1. 輸入圖像數(shù)組,對彩色圖像灰度化;
2. 對灰度化以后的圖像,計算圖像梯度,這里使用sobol算子;
3. 對得到每一個非零像素點實現(xiàn)半徑為R的范圍內(nèi)的掃描,找出與之最相近的為零的原像素值;
4. 對得到數(shù)組進行簡單的掃描,得到主色彩。
其中參數(shù)R是要根據(jù)不同應(yīng)用場景,找到最合適的值。理論上圖像越大,R的取值也應(yīng)該越大,否則算法會失準。
三:原圖及運行效果

原圖

算法運行之后提取到四種主要色彩
四:算法實現(xiàn)源代碼
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);
// 創(chuàng)建處理結(jié)果
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();
}
}
注意:主要的關(guān)鍵在于對待處理圖像輸入正確大小的半徑,這個半徑大小跟圖像實際大小相關(guān),而且算法可以近一步優(yōu)化成不依賴半徑參數(shù)的版本,知道找到等于零的像素為止。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Java swing 圖像處理多種效果實現(xiàn)教程
- java如何用Processing生成馬賽克風格的圖像
- JAVA演示阿里云圖像識別API,印刷文字識別-營業(yè)執(zhí)照識別
- Java實現(xiàn)圖片旋轉(zhuǎn)、指定圖像大小和水平翻轉(zhuǎn)
- java通過jni調(diào)用opencv處理圖像的方法
- JavaSE圖像驗證碼簡單識別程序詳解
- Java圖像之自定義角度旋轉(zhuǎn)(實例)
- Java OCR tesseract 圖像智能文字字符識別技術(shù)實例代碼
- 詳解使用JavaCV/OpenCV抓取并存儲攝像頭圖像
- java 使用ImageIO.writer從BufferedImage生成jpeg圖像遇到問題總結(jié)及解決
- Java利用AlphaComposite類合并圖像
相關(guān)文章
SpringBoot項目改為SpringCloud項目使用nacos作為注冊中心的方法
本文主要介紹了SpringBoot項目改為SpringCloud項目使用nacos作為注冊中心,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-04-04
JAVA Spring Boot 自動配置實現(xiàn)原理詳解
這篇文章主要介紹了詳解SpringBoot自動配置原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2021-09-09
Java使用FileInputStream流讀取文件示例詳解
這篇文章主要介紹了Java使用FileInputStream流讀取文件示例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07
Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)
XMLType是Oracle支持的一種基于XML格式存儲的數(shù)據(jù)類型,這里我們共同來探究Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)的方法:2016-07-07

