简单图像滤镜功能的Java实现
圖像濾鏡功能Java實(shí)現(xiàn)
前置內(nèi)容
-
RGB圖片: 對(duì)于圖片中的像素, 使用Red, Green, Blue 三種顏色共同得到一個(gè)最終的顯示顏色, 其數(shù)值均在0 - 255 之間
-
在Java中對(duì)于圖像的處理可以在使用IO流得到的BufferedImage類的實(shí)例操作, 也可以讀入矩陣進(jìn)行操作
-
BufferedImage類實(shí)例中會(huì)提供一個(gè)Graphics實(shí)例, 可以直接對(duì)BufferedImage實(shí)例進(jìn)行操作
操作前的原圖
對(duì)單點(diǎn)像素處理的濾鏡算法
在這類方法中, 對(duì)于每個(gè)像素的處理只與這個(gè)像素本身有關(guān), 與圖片的其他信息無(wú)關(guān), 于是可以簡(jiǎn)單對(duì)每個(gè)像素進(jìn)行遍歷, 按照預(yù)定的方法進(jìn)行逐個(gè)處理
public void pixelRasterize(BufferedImage bufImg, String op) {Graphics g = bufImg.getGraphics();for (int i = 0; i < bufImg.getWidth(); i++) {for (int j = 0; j < bufImg.getHeight(); j++) {int pixelVal = bufImg.getRGB(i, j);int red = (pixelVal >> 16) & 0xFF;int green = (pixelVal >> 8) & 0xFF;int blue = pixelVal & 0xFF;Color color = pixelShader(red, green, blue, op);bufImg.setRGB(i, j, color.getRGB());}}this.bufImg = bufImg;}RGB拆分
- 對(duì)于圖片中的像素, RGB數(shù)值使用一個(gè)int來表示, 由于其每種顏色只需要0 - 255, 所以僅使用了 1 byte 進(jìn)行封裝, 最高的8位置1, 次高的每8位依次為Red, Green, Blue
這些功能中都只需要對(duì)單個(gè)像素進(jìn)行處理: 灰度化, 二值化, 去除深色背景, 負(fù)片, 復(fù)古, 明亮
public Color pixelShader(int red, int green, int blue, String op) {switch (op) {case "Original":case "Second":return new Color(red, green, blue);case "Gray":int gray = (red + green + blue) / 3;return new Color(gray, gray, gray);case "Binary":gray = (red + green + blue) / 3;if (gray < 70)return new Color(0, 0, 0);else return new Color(255, 255, 255);case "Rid Bg":gray = (red + green + blue) / 3;if (gray > 63)return new Color(red, green, blue);else return new Color(225, 225, 225);case "Negative":red = 255 - red;green = 255 - green;blue = 255 - blue;return new Color(red, green, blue);case "OldFashion":int R = (int) (0.393 * red + 0.469 * green + 0.049 * blue);int G = (int) (0.349 * red + 0.586 * green + 0.068 * blue);int B = (int) (0.272 * red + 0.534 * green + 0.031 * blue);return new Color(R, G, B);case "Bright":red = Math.min(255, red + 10);blue = Math.min(255, blue + 10);green = Math.min(255, green + 10);return new Color(red, green, blue);}return null;}-
灰度化
對(duì)于一個(gè)像素, 僅保留一個(gè)色彩通道的值, 使其三個(gè)色彩混合后只留下明暗信息
常見做法為, 使用一個(gè)通道的數(shù)值代替所有通道, 或者平均其在三個(gè)通道上的數(shù)值
-
二值化
將整個(gè)圖片的像素顏色進(jìn)行二分類, 使其被轉(zhuǎn)變?yōu)榧兒诨蛘呒儼椎男畔? 分類標(biāo)準(zhǔn)一般按照需求來制定
常見做法為, 像素的灰度值高于一定數(shù)值將被認(rèn)為是黑色, 否則為白色
-
去除背景
不基于機(jī)器學(xué)習(xí)的簡(jiǎn)單背景去除往往也不需要進(jìn)行輪廓勾勒, 可以根據(jù)一定的需求去除一定范圍內(nèi)的顏色
比如, 灰度值高于一定數(shù)值可以渲染原色, 而低于一定數(shù)值會(huì)被去除
-
負(fù)片
負(fù)片的效果為顏色反轉(zhuǎn), 只需要使用其RGB的顏色使用最大深度減去原色數(shù)值即可
這圖突然有點(diǎn)奇怪
-
復(fù)古
此類特效屬于數(shù)值調(diào)整類特效, 一般做法只需要按照目前成熟的參數(shù)進(jìn)行調(diào)整即可
-
明亮
此特效需要整體上調(diào)所有通道的數(shù)值使其更偏向于白色
常用方法為給所有通道加上固定的值, 但注意不要超過255
對(duì)區(qū)域進(jìn)行采樣后實(shí)現(xiàn)的濾鏡算法
一些算法需要對(duì)圖片中的某些像素進(jìn)行采樣, 然后用采樣并處理過的數(shù)據(jù)進(jìn)行濾鏡操作, 這類算法一定是有損圖片質(zhì)量的
public void areaSamplingRasterize(BufferedImage bufImg, String op, boolean recOrOval, int sampleSize, int fillSize) {Random rand = null;BufferedImage orgImg = new BufferedImage(bufImg.getWidth(), bufImg.getHeight(), BufferedImage.TYPE_INT_RGB);Graphics g = orgImg.getGraphics();g.drawImage(bufImg, 0, 0, null);g = bufImg.getGraphics();if (op == "Oil")rand = new Random();for (int i = 0; i < orgImg.getWidth(); i += sampleSize) {for (int j = 0; j < orgImg.getHeight(); j += sampleSize) {g.setColor(pixelShader(orgImg.getRGB(i, j), op));if (recOrOval) {g.fillRect(i, j, fillSize, fillSize);} else {int fs = fillSize;if (op.equals("Oil"))fs = rand.nextInt(fillSize) + sampleSize;g.fillOval(i, j, fs, fs);}}}this.bufImg = bufImg;}-
油畫
油畫風(fēng)格的特點(diǎn)是著色精細(xì)度相對(duì)較粗糙, 所以可以通過對(duì)圖片進(jìn)行一定的隨機(jī)區(qū)域著色的方法來進(jìn)行制作
常見方法為, 對(duì)一定的采樣大小區(qū)域內(nèi), 填充隨機(jī)大小的圓形區(qū)域, 顏色為區(qū)域內(nèi)的一個(gè)采樣點(diǎn)的顏色, 注意填充時(shí)應(yīng)盡量覆蓋采樣區(qū)域以免留下空白(或者使用原畫作為底片), 也可以進(jìn)行一點(diǎn)點(diǎn)的偏色處理
-
馬賽克
馬賽克的簡(jiǎn)單實(shí)現(xiàn)就是將一個(gè)采樣區(qū)域內(nèi)填充成同一種采樣色, 同樣可以進(jìn)行適當(dāng)?shù)钠?br />
對(duì)區(qū)域處理實(shí)現(xiàn)的濾鏡算法
圖像卷積
使用一定的卷積窗口(權(quán)重矩陣) 對(duì)一個(gè)區(qū)域內(nèi)的圖像進(jìn)行特征的提取, 綜合或過濾
public void areaConvRasterize(BufferedImage bufImg, String op, int kernelSize, double[] rights) {BufferedImage orgImg = new BufferedImage(bufImg.getWidth(), bufImg.getHeight(), BufferedImage.TYPE_INT_RGB);Graphics g = orgImg.getGraphics();g.drawImage(bufImg, 0, 0, null);for (int i = 0; i < orgImg.getWidth(); i++) {for (int j = 0; j < orgImg.getHeight(); j++) {int reds = 0, greens = 0, blues = 0;int edgeSize = (int) Math.sqrt(kernelSize);int mx = Math.min(orgImg.getWidth(), i + edgeSize);int my = Math.min(orgImg.getHeight(), j + edgeSize);ArrayList<Integer> pixelVal = new ArrayList(kernelSize);for (int nx = i; nx < mx; nx++) {for (int ny = j; ny < my; ny++) {pixelVal.add(orgImg.getRGB(nx, ny));}}while (pixelVal.size() < kernelSize) {pixelVal.add(orgImg.getRGB(i, j));}int x = Math.min(mx - 1, i + edgeSize / 2);int y = Math.min(my - 1, j + edgeSize / 2);bufImg.setRGB(x, y, convPixelShader(kernelSize, pixelVal, op, new int[]{x, y}).getRGB());}}this.bufImg = bufImg;}常見的卷積一般以卷積窗口覆蓋的中心作為目標(biāo)對(duì)象, 所以對(duì)于邊界來說, 處理方法一般為認(rèn)為圖片無(wú)限重復(fù)或者直接拋棄邊界
public Color convPixelShader(int kernelSize, ArrayList<Integer> pixelVal, String op, int[] centerPos) {int radius = (int) Math.sqrt(kernelSize);double[] rights = new double[kernelSize];int reds = 0, greens = 0, blues = 0;switch (op) {case "Sharpen":Arrays.fill(rights, 0, kernelSize, -1);rights[kernelSize >> 1] = 9;break;case "Blur":int l = 0;for (int x = -radius >> 1; x < radius >> 1; x++) {for (int y = 0; y < radius; y++) {rights[l++] = Math.pow((int) Math.E, -(x * x + y * y) / (2 * GuassBlur.sigma * GuassBlur.sigma))/ (2 * pi * GuassBlur.sigma * GuassBlur.sigma);}}break;}for (int i = 0; i < kernelSize; i++) {reds += ((pixelVal.get(i) >> 16) & 0xFF) * rights[i];greens += ((pixelVal.get(i) >> 8) & 0xFF) * rights[i];blues += (pixelVal.get(i) & 0xFF) * rights[i];}reds += 20;greens += 20;blues += 20;reds = Math.min(255, reds);reds = Math.max(0, reds);greens = Math.min(255, greens);greens = Math.max(0, greens);blues = Math.min(255, blues);blues = Math.max(0, blues);return new Color(reds, greens, blues);}-
銳化
銳化操作的目的是增強(qiáng)圖片中不同顏色間邊界的對(duì)比度, 突出邊界
其卷積核相對(duì)固定,常用為 3x3 卷積 的 (1,1)位置為9, 其他位置為 -1 的權(quán)重矩陣
-
模糊
模糊操作的實(shí)現(xiàn)有很多, 以高斯模糊為例, 其需要通過計(jì)算某像素相鄰位置對(duì)該像素的影響來得到結(jié)果,其公式為
? (x,y)為卷積核的中心坐標(biāo), 一般作為坐標(biāo)原點(diǎn)
效果一般取決于模糊半徑和σ
總結(jié)
以上是生活随笔為你收集整理的简单图像滤镜功能的Java实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 软件奇谈
- 下一篇: 程序员路在何方的辛苦工作