影像處理方法java(一)
目錄
- 影像處理方法java(一)
- 1.引言
- 2.基本原理
- 2.1影像的基本原理
- 2.2影像資料的處理
- 2.3位運算
- 3.圖片讀寫與濾鏡效果
- 3.1圖片讀寫
- 3.2濾鏡效果
- 3.2.1原圖輸出
- 3.2.2馬賽克
- 3.2.3灰度
- 3.2.4濾鏡顏色
- 3.2.5輪廓
- 4.互動式處理
- 4.1帶按鈕的表單
- 4.2動作監聽器
- 4.3綜合起來
- 4.3.1創建ImageUtils類
- 4.3.2創建ImageListener類
- 4.3.3創建ImageUI類
- 4.3.4運行結果
- 5.心得體會
1.引言
??初學java,想做一個簡易的美顏相機,對影像處理的一些方法進行了相應的學習,主要包括影像的原理、影像的資料處理、位運算、濾鏡效果、圖片讀寫等,
2.基本原理
2.1影像的基本原理
??每一張影像,其實都是由一個個的帶有顏色的點組成的矩陣,也就是我們常說的像素點矩陣,同時橫縱坐標像素點的個數乘積就是影像的解析度,
??每一個像素點的顏色,都是有相應的編號的,一般的存盤格式是RGB和ARGB格式,RGB格式:RGB其實就是三原色,Red、Green、Blue,每一種原色的編號范圍是0-255,也就是存盤在一個位元組(8位2進制)中,Red從0到255顏色會越來越“紅”,紅的程度會加深,
??舉個例子來說,對于RGB: 123, 200,13 來說,這個顏色是由Red123,Green200,Blue13這三種顏色合成的,
??所以我們很容易知道,RGB是占三個位元組,可以存盤在整型變數(四個位元組)中,并且存盤在低24位,那么就會出現高8位沒有使用的情況,ARGB格式就是把高8位也利用起來,用來存其他的資訊例如照片拍攝日期等等,
2.2影像資料的處理
??初始化生成一個表單,然后通過亂數隨機生成一張RGB格式的圖片,通過位移運算計算RGB格式里red、green、blue的值(位移運算在2.3會講解),對于濾鏡等操作,就可以通過調節red、green、blue的值來實作,比如說red=red/2,就能實作圖片紅色降度,也就是照片的紅色不會太鮮艷,
??我們常常也會聽說灰度圖片,就是照片會變成灰色,這種照片的每一個像素點的RGB值均滿足red=green=blue,我們可以調整三原色的占比來確定灰階(詳見代碼),
??二維碼:有了灰階,也就是對每一個像素值都有唯一標準了,我們可以確定一個分界值a,當算出的灰度值大于a,就用白色來表示;若小于a,就用黑色來表示,并且使用fiilRect方法的時候,把像素點的寬和高調大一點,我們就可以得到這張圖片的二維碼了,也就是說,這個二維碼儲存了我這張圖片的資料,
import javax.swing.*;
import java.awt.*;
import java.util.Random;
import javax.swing.JFrame;
public class ImageUI extends JFrame {
//初始化一個表單
public void initUI(){
setTitle("影像編程");
setSize(1000,1000);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/*
* 表單出現在螢屏上時呼叫
* 繪制表單本身
* 在表單上繪制像素點
* @param g :圖形物件 可以來繪制圖形
* Graphics 圖形
* g.fillRect(x,y,w,h);
*/
public void paint(Graphics g){
super.paint(g);
//g.fillRect(100,100,10,10);
int[][] imgarr=new int[300][300];
// 隨機創建顏色矩陣
Random random = new Random();
for (int i = 0; i < 300; i++) {
for (int j = 0; j < 300; j++) {
int colorValue = random.nextInt(256*256*256);
imgarr[i][j]=colorValue;
Color color = new Color(colorValue);
g.setColor(color);
g.fillRect(50+i,50+j,1,1);
}
}
for (int i = 0; i <imgarr.length; i+=10) {
for (int j = 0; j < imgarr[i].length; j+=10) {
int value = imgarr[i][j];
int red =(value>>16)&0xFF;
int green =(value>>8)&0xFF;
int blue =(value>>0)&0xFF;
// 灰度 r=g=b
// 有了灰階 一張照片所有的像素值都具有同樣的標準了
int gray =(int)(red*0.36+green*0.29+blue*0.35);
if(gray>128){
g.setColor(Color.white);
}
else{
g.setColor(Color.black);
}
g.fillRect(400+i,50+j,10,10);
}
}
}
// 啟動程式
public static void main(String[] args) {
ImageUI img = new ImageUI();
img.initUI();
}
}
運行圖片

2.3位運算
??這里主要講如何通過存盤RGB的整型int得到red、green、blue的值;以及red、green、blue如何合成為一個int,
??我們了解了RGB的存盤原理,很容易知道:17-24位存red,9-16位存green,1-8位存blue,用除法和減法可以提取出red、green、blue,但是這樣運算速度會慢一些,可以用位移運算,運算速度會快一些,
??假設RGB的值存盤在int value中,通過位移運算有:
??????int red =(value>>16)&0xFF;
??????int green =(value>>8)&0xFF;
??????int blue =(value>>0)&0xFF;
為什么要位移之后與0xFF求與運算呢? 仔細分析后,我們知道,與0xFF做與運算后,可以將除低8位以外的所有位的數字變為0,
??所以我們以此類推,我們發現把red、green、blue合成一個RGB時,可以通過位移加上或運算來實作:
??????int rgb= (red<<16)|(green<<8)|blue;
3.圖片讀寫與濾鏡效果
3.1圖片讀寫
??圖片的輸入,我寫了一個輸入圖片的方法,加上想要讀取的圖片路徑,路徑是相對路徑和絕對路徑都可以,我的圖片和代碼是放在一個檔案夾里的,所以用的相對路徑,
使用ImageIO.read()方法的時候,需要創建BufferedImage類的物件
int[][] imgarr = getImagePixArr("picture4.jpeg");
//這里imgarr是創建的二維陣列,用來存盤圖片的像素點矩陣,
public int[][] getImagePixArr(String path){
// 宣告一個檔案物件
File file = new File(path);
BufferedImage buffimg=null;
try {// 處理檔案IO例外
// 讀取為 buffimg 物件
buffimg = ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
// 寬 高 圖片型別 ARGB
int w = buffimg.getWidth();
int h = buffimg.getHeight();
// 根據 圖片物件的寬 高 生成一個二維陣列 -- 線性結構
int[][] imgarr = new int[w][h];
// 遍歷存盤像素值
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
imgarr[i][j]= buffimg.getRGB(i,j);
}
}
return imgarr;
}
??圖片輸出的話也是一樣,也需要創建BufferedImage類的物件,代碼如下:
public void outImagePixArr(int[][] imgarr ,String path){
// 宣告一個檔案物件
File file = new File(path);
BufferedImage buffimg = new BufferedImage(imgarr.length ,imgarr[0].length ,BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i < imgarr.length; i++){
for (int j = 0; j < imgarr[i].length; j++){
buffimg.setRGB(i, j, imgarr[i][j]);
}
}
try {// 處理檔案IO例外
// 讀取為 buffimg 物件
ImageIO.write(buffimg, "PNG", file);
} catch (IOException e) {
e.printStackTrace();
//return;
}
}
3.2濾鏡效果
3.2.1原圖輸出
// 原圖
for (int i = 0; i < imgarr.length; i++) {
for (int j = 0; j < imgarr[i].length; j++) {
Color color = new Color(imgarr[i][j]);
g.setColor(color);
g.fillRect(i,j,1,1);
}
}
3.2.2馬賽克
??馬賽克就是模糊處理,把一個像素點的長寬變大即可,
// 馬賽克
for (int i = 0; i < imgarr.length; i+=10) {
for (int j = 0; j < imgarr[i].length; j+=10) {
Color color = new Color(imgarr[i][j]);
g.setColor(color);
g.fillRect(750+i,j,10,10);
}
}
3.2.3灰度
??在前面已經講過,灰度圖片的red=green=blue,
// 灰度
for (int i = 0; i < imgarr.length; i++) {
for (int j = 0; j < imgarr[i].length; j++) {
int value = imgarr[i][j];
int red=(value>>16)&0xFF;
int green=(value>>8)&0xFF;
int blue=(value>>0)&0xFF;
int gray = (red+green+blue)/3;
Color color = new Color(gray,gray,gray);
g.setColor(color);
g.fillRect(i,400+j,1,1);
}
}
3.2.4濾鏡顏色
??這個濾鏡是我自己調的,可能不是很好看,red變為原來的0.8,green變成原來的0.5,blue變成原來的0.6,
//濾鏡
for (int i = 0; i < imgarr.length; i++){
for (int j = 0; j < imgarr[i].length; j++){
int value = imgarr[i][j];
int red=(value>>16)&0xFF;
int green=(value>>8)&0xFF;
int blue=(value>>0)&0xFF;
red = red*4/5;
green = green/2;
blue = blue*3/5;
//imgarr1 = (red<<16)|(green<<8)|blue;
Color color = new Color(red,green,blue);
g.setColor(color);
g.fillRect(i,400+j,1,1);
}
}
3.2.5輪廓
//輪廓
for (int i = 0; i < imgarr.length-2; i++) {
for (int j = 0; j < imgarr[i].length-2; j++) {
int value = imgarr[i][j];
int red=(value>>16)&0xFF;
int green=(value>>8)&0xFF;
int blue=(value>>0)&0xFF;
int gray = (red+green+blue)/3;
int nvalue = imgarr[i+2][j+2];
int nred=(nvalue>>16)&0xFF;
int ngreen=(nvalue>>8)&0xFF;
int nblue=(nvalue>>0)&0xFF;
int ngray = (nred+ngreen+nblue)/3;
if(Math.abs(gray-ngray)>10){
g.setColor(Color.white);
}else{
g.setColor(Color.black);
}
// Color color = new Color(ngray,ngray,ngray);
g.fillRect(750+i,400+j,1,1);
}
}
運行圖片


4.互動式處理
4.1帶按鈕的表單
??創建一個UI類,可以生成帶按鈕的表單,那個布局方法是自動把按鈕布局,
import javax.swing.*;
import java.awt.*;
import javax.swing.JFrame;
public class UI extends JFrame{
// 構造方法
// 創建物件時呼叫
String[] strs={"原圖","灰度","懷舊","馬賽克","二值化","融合","輪廓"};
public void initUI() {
setTitle("影像表單");
setSize(2200, 1000);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//布局
FlowLayout fl =new FlowLayout();
setLayout(fl);
for (int i = 0; i < strs.length; i++) {
JButton btn = new JButton(strs[i]);
add(btn);
}
setVisible(true);
}
public static void main(String[] args) {
UI img = new UI();
img.initUI();
}
}
運行結果

但是我們在表單上點擊按鈕,是沒有反應的,于是我們需要一個Listener類,也就是監聽器,來監聽按鈕是否被點擊,如果被點擊就會進行相應操作,
4.2動作監聽器
??ActionListener——動作監聽器,作用是監聽按鈕是否被點擊了,如果被點擊了就呼叫一個預設好的方法(方法的內容需要自己來寫 ),實作介面interface時,用implements關鍵字,可以變相實作多繼承,
import java.awt.event.ActionListener;
// 1:首先創建一個類 使用 implements ActionListener
public class ImageListener implements ActionListener{
// 2:重寫ActionListener 中的方法
public void actionPerformed(ActionEvent e){
// 3: 點什么按鈕就繪制什么影像
System.out.println("點擊了按鈕 ");
}
}
運行結果:點一下按鈕就會輸出“點擊了按鈕 ”
4.3綜合起來
??前文講了很多細節的處理以及方法,現在我們就可以創建一個表單,一個有按鈕的表單,點擊按鈕能得到相應“濾鏡”的圖片,不再是4.1那樣沒有反應的按鈕;也不再是4.2只輸出一句話,我們重寫方法后,可以把圖片輸出在表單上,
4.3.1創建ImageUtils類
??創建這個工具類目的有兩個:第一,讀取某個路徑下的圖片,把他存在我們的像素點矩陣imgarr(二維陣列)中,這個我在3.1中有介紹;第二,就是能把處理后的像素點矩陣“畫出來”,也就是圖片,
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ImageUtils {
public int[][] getImagePixArr(String path){
// 宣告一個檔案物件
File file = new File(path);
BufferedImage buffimg=null;
try {// 處理檔案IO例外
// 讀取為 buffimg 物件
buffimg = ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
// 寬 高 圖片型別 ARGB
int w = buffimg.getWidth();
int h = buffimg.getHeight();
// 根據 圖片物件的寬 高 生成一個二維陣列 -- 線性結構
int[][] imgarr = new int[w][h];
// 遍歷存盤像素值
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
imgarr[i][j]= buffimg.getRGB(i,j);
}
}
return imgarr;
}
public void drawImage0(int[][] imgarr,Graphics g){
for (int i = 0; i < imgarr.length; i++) {
for (int j = 0; j < imgarr[i].length; j++) {
Color color = new Color(imgarr[i][j]);
g.setColor(color);
g.fillRect(100+i,100+j,1,1);
}
}
}
}
4.3.2創建ImageListener類
??創建這個動作監聽器類,作用是監聽按鈕是否被點擊了,如果點擊了就呼叫相應的方法,我們在4.2中重寫了方法,點擊就會輸出“點擊了按鈕 ”;現在,我們再次重寫方法,點擊相應的按鈕,就輸出對應按鈕的圖片,(這里我只重寫了輸出原圖的方法,輸出其他“濾鏡”圖片的方法只需要把3.2中的代碼粘貼修改即可)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ImageListener implements ActionListener{
Graphics gr;
ImageUtils imageUtils = new ImageUtils();
int[][] imgarr=null;
{ // 初始化的代碼塊 創建物件時執行
imgarr = imageUtils.getImagePixArr("picture4.jpeg");
}
// 2:重寫ActionListener 中的方法
public void actionPerformed(ActionEvent e){
// 3: 點什么按鈕就繪制什么影像
// 如何區分 按鈕
//獲取按鈕的字串
String btnstr = e.getActionCommand();
//System.out.println("點擊了 按鈕 "+btnstr);
if(btnstr.equals("原圖")){
// 繪制原圖
// gr.drawString(btnstr,200,200);
imageUtils.drawImage0(imgarr,gr);
}
}
}
4.3.3創建ImageUI類
??創建這個類,其實就是輸出帶有按鈕的表單,參考4.1,代碼如下:
import javax.swing.*;
import java.awt.*;
public class ImageUI extends JFrame {
// 構造方法
// 創建物件時呼叫
String[] strs={"原圖","灰度","懷舊","馬賽克","二值化","融合","輪廓"};
public ImageUI(String title) {
setTitle(title);
setSize(1000, 1000);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//布局
FlowLayout fl =new FlowLayout();
setLayout(fl);
// 監聽器物件
ImageListener imageL = new ImageListener();
for (int i = 0; i < strs.length; i++) {
JButton btn = new JButton(strs[i]);
btn.setBackground(Color.white);
btn.addActionListener(imageL);// 所有的按鈕都注冊了監聽器
add(btn);
}
setVisible(true);
// 獲取畫筆
Graphics g = this.getGraphics();
imageL.gr=g;
}
public static void main(String[] args) {
new ImageUI("影像處理編程");
}
}
4.3.4運行結果
??(1)沒有點擊按鈕時:

??(2)點擊按鈕“原圖”時:

5.心得體會
??本文到這里就結束了,后面博客會補充更“厲害”的影像處理方法,如PS等,一介java小白,歡迎大家批評指正,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/293067.html
標籤:其他
上一篇:你真的懂語音特征嗎?
下一篇:vmware虛擬軟體的網路模式
