用10種程式語言做影像二值化(Image binarization)
用10種程式語言做影像二值化(Image binarization)¶
簡介¶
有些時候,我們需要將彩色影像轉換為黑白影像,這很簡單,利用門檻值的方法就可以做到。
作法¶
Visual C++ 2010¶
// 影像的高度
for ( int iY = 0; iY < imageA->DibInfo->bmiHeader.biHeight; iY++ )
{
// 影像的寬度
for ( int iX = 0; iX < imageA->DibInfo->bmiHeader.biWidth; iX++ )
{
// 影像的索引值,因為這張影像的24 bit ,所以要乘以3
lIDXA = ( iX * 3 ) + ( iY * imageA->DibInfo->bmiHeader.biWidth * 3 );
// 取得藍色像素值
byteRGB_BA = imageA->DibArry[lIDXA+0];
// 取得綠色像素值
byteRGB_GA = imageA->DibArry[lIDXA+1];
// 取得紅色像素值
byteRGB_RA = imageA->DibArry[lIDXA+2];
// 將RGB利用YUV公式轉換Y(灰階)
dobYUV_YA = (0.299 * byteRGB_RA + 0.587 * byteRGB_GA + 0.114 * byteRGB_BA);
// 利用雙門檻值,灰階轉換黑白
if ( dobYUV_YA > 60 && dobYUV_YA < 160 )
{
lIDXB = ( iX * 3 ) + ( iY * imageB->DibInfo->bmiHeader.biWidth * 3 );
imageB->DibArry[lIDXB+0] = 255;
imageB->DibArry[lIDXB+1] = 255;
imageB->DibArry[lIDXB+2] = 255;
}
// 門檻值之外的填為黑色
else
{
lIDXB = ( iX * 3 ) + ( iY * imageB->DibInfo->bmiHeader.biWidth * 3 );
imageB->DibArry[lIDXB+0] = 0;
imageB->DibArry[lIDXB+1] = 0;
imageB->DibArry[lIDXB+2] = 0;
}
} // 影像的寬度
} // 影像的高度
C++ Builder XE5¶
//---------------------------------------------------------------------------
#include < vcl.h >
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
// 建立三個 TBitmap object 的指標
Graphics::TBitmap *TheBitmap, *TempBitmap, *OriginBitmap;
// 宣告一個門檻值變數
int Threshold;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Exit1Click(TObject *Sender)
{
// 離開程式
Close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::OpenFile1Click(TObject *Sender)
{
// 利用圖檔開啟對話框,開啟圖檔
if ( OpenPictureDialog1->Execute() )
{
// 關閉自動調整大小
Image1->AutoSize=false;
// 啟用伸展調整
Image1->Stretch=true;
// 載入開啟的圖檔
Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
// 設定影像指標,指向開啟的圖檔
TheBitmap=Image1->Picture->Bitmap;
// 建立一個 TBitmap object 保留原始影像
OriginBitmap = new Graphics::TBitmap();
// 保留原始影像
OriginBitmap->Assign(TheBitmap);
// 設定 TImage object 保留原始影像
Image1->Picture->Bitmap->Assign(TheBitmap);
// 如果檔案開啟成功,就設定一個旗標值
// 代表成功地開啟了一個檔案
OpenFile = 1;
// 設定門檻值
Threshold = 100;
// 設定水平滑動軸的位置為門檻值
ScrollBar1->Position = Threshold;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ScrollBar1Change(TObject *Sender)
{
// 如果開啟檔案旗標為零,則退出副程式
if (OpenFile == 0) {
return;
}
Byte *ptr, *tptr;
// 由水平滑動軸獲得門檻值
Threshold = (int) ScrollBar1->Position;
// 設定 TImage 回復為原始影像
Image1->Picture->Bitmap->Assign(OriginBitmap);
// 建立暫存影像
TempBitmap = new Graphics::TBitmap();
// 暫存影像轉存至當下的影像
TempBitmap->Assign(TheBitmap);
// 影像的高度
for (int y=0; y < TheBitmap->Height; y++) {
// 設定水平掃描線的指標,指向 TheBitmap
ptr = (Byte*) TheBitmap->ScanLine[y];
// 設定水平掃描線的指標,指向暫存 TempBitmap
tptr = (Byte*) TempBitmap->ScanLine[y];
// 影像的寬度
for (int x=0; x < TheBitmap->Width; x++) {
// 假如暫存影像像素大於門檻值,就分類為白色
if (tptr[x] > Threshold) {
ptr[x] = (Byte) 255;
}
// 若暫存影像像素小於門檻值,就分類為黑色
else
{
ptr[x] = (Byte) 0;
}
} // 影像的寬度
} // 影像的高度
// 釋放暫存影像指標
delete TempBitmap;
// 重繪視窗
Repaint();
// 設定二值化後的影像結果給 Image1
Image1->Picture->Bitmap->Assign(TheBitmap);
}
//---------------------------------------------------------------------------
Visual C# 2012¶
namespace Binarization_for_C_Sharp
{
public partial class Form1 : Form
{
// 宣告檔名字串
private string curFileName;
// 宣告 bitmap object.
private System.Drawing.Bitmap curBitmap;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// 建立一個檔案開啟對話框
OpenFileDialog openDlg = new OpenFileDialog();
// 設應檔案開啟對話框過濾副檔名的條件
openDlg.Filter = "All format | *.bmp; *.pcx; *.png; *.jpg; *.gif;" +
"*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf";
// 設定檔案開啟對話框的標題
openDlg.Title = "Open a picture file.";
// 如果檔案對話框開啟圖檔成功
if (openDlg.ShowDialog() == DialogResult.OK)
{
// 將檔名設定給檔名字串
curFileName = openDlg.FileName;
try
{
// 經由檔名建立BMP影像物件
curBitmap = (Bitmap)Image.FromFile(curFileName);
}
// 如果獲得例外
catch (Exception exp)
{
// 跳出並顯示錯誤訊息
MessageBox.Show(exp.Message);
}
}
// 重繪視窗
Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// 從外部物件建立一個 graphics object
Graphics g = e.Graphics;
// 如果圖檔開啟成功
if (curBitmap != null)
{
// 將開啟的圖檔繪製到 Graphics 的物件中
g.DrawImage(curBitmap, 140, 10, curBitmap.Width, curBitmap.Height);
}
}
private void button2_Click(object sender, EventArgs e)
{
// 如果圖檔開啟成功
if (curBitmap != null)
{
// 建立一個 color object.
Color curColor;
int ret;
// 影像的寬度
for (int iX = 0; iX < curBitmap.Width; iX++)
{
// 影像的高度
for ( int iY = 0; iY < curBitmap.Height; iY++ )
{
// 獲得RGB像素值
curColor = curBitmap.GetPixel(iX, iY);
// 轉換RGB到YUV的Y(灰階)
ret = (int) (curColor.R * 0.299 + curColor.G * 0.578 + curColor.B * 0.114);
// 設定一個單門檻值,大於則為白色,小於則黑色
if (ret > 120)
{
ret = 255;
}
else
{
ret = 0;
}
// 寫入新的像素值
curBitmap.SetPixel( iX, iY, Color.FromArgb ( ret, ret ,ret ) );
} // 影像的寬度
} // 影像的高度
// 重繪視窗
Invalidate();
}
}
}
}
Visual Basic .NET 2012¶
Public Class Form1
' 建立一個檔名字串
Private curFileName As String
' 建立一個 bitmap object
Private curBitmap As Bitmap
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 建立一個開啟檔案對話框
Dim openFileDialog1 As New OpenFileDialog()
' 設定對話框初始目錄
openFileDialog1.InitialDirectory = ".\"
' 設定對話框過濾副檔名
openFileDialog1.Filter = "All format | *.bmp; *.pcx; *.png; *.jpg; *.gif;" +
"*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf"
' 設定對話框過濾副檔名的索引值,預設是1
openFileDialog1.FilterIndex = 1
' 設定對話框每次開啟的時候,都回到最後開啟檔案的目錄
' 預設值是否(false)
openFileDialog1.RestoreDirectory = True
' 如果檔案成功的開啟
If openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
Try
' 設定對話框開啟的檔名給檔名字串
curFileName = openFileDialog1.FileName
' 確認檔名不是空白
If (curFileName IsNot Nothing) Then
' 經由檔名建立一個BMP物件,名為b
Dim b As Bitmap = New Bitmap(curFileName)
' 經由b建立一個大小及色彩空間相同的BMP物件
curBitmap = New Bitmap(b.Width, b.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
' 將b複製到BMP物件
curBitmap = b.Clone()
End If
' 如果出現例外,就顯示錯誤訊息
Catch Ex As Exception
MessageBox.Show("Cannot read file from disk. Original error: " & Ex.Message)
Finally
End Try
' 重繪視窗
Invalidate()
End If
End Sub
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
' 如果圖檔成功開啟
If (curBitmap IsNot Nothing) Then
' 將BMP繪製在Graphics物件中
e.Graphics.DrawImage(curBitmap, 140, 10, curBitmap.Width, curBitmap.Height)
End If
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' 影像的高度
For y As Integer = 0 To curBitmap.Height - 1
' 影像的寬度
For x = 0 To curBitmap.Width - 1
' 獲得RGB像素值
Dim curPixColor As Color = curBitmap.GetPixel(x, y)
' 宣告灰階像素值變數
Dim ret As Integer
' 轉換RGB到YUV的Y(灰階)
ret = (curPixColor.R * 0.299 + curPixColor.G * 0.578 + curPixColor.B * 0.114)
' 像素值若大於門檻值,則為白色,反之,黑色
If ret > 120 Then
curBitmap.SetPixel(x, y, Color.White)
Else
curBitmap.SetPixel(x, y, Color.Black)
End If
' 影像的寬度
Next
' 影像的高度
Next
' 重繪視窗
Invalidate()
End Sub
End Class
Visual Basic 6.0¶
' 當表單載入時的副程式
Private Sub Form_Load()
' 經由檔名載入影像
Picture1.Picture = LoadPicture(App.Path & "\B_01.bmp")
' 宣告X軸變數
Dim lngX As Long
' 宣告Y軸變數
Dim lngY As Long
' 宣告灰階變數
Dim intS
' 分別宣告RGB變數
Dim intR, intG, intB
' Set up the scale mode is pixel.
Picture1.ScaleMode = 3
' 設定圖形框自動重繪
Picture1.AutoRedraw = True
' 設定圖形框的單位為像素
Picture2.ScaleMode = 3
' 設定圖形框自動重繪
Picture2.AutoRedraw = True
' 影像的高度
For lngY = 0 To Picture1.ScaleHeight
' 影像的寬度
For lngX = 0 To Picture1.ScaleWidth
' 取得紅色像素值
intR = (Picture1.Point(lngX, lngY) And &HFF)
' 取得綠色像素值
intG = (Picture1.Point(lngX, lngY) And &HFF00&) \ 256
' 取得藍色像素值
intB = (Picture1.Point(lngX, lngY) And &HFF0000) \ 65536
' RGB轉換為灰階值
intS = (intR + intG + intB) / 3
' 灰階值大於門檻值,則為白色
If intS > 120 Then
intS = 255
' 反之,則為黑色
Else
intS = 0
End If
' 將黑白像素值寫入圖形框
Picture2.PSet (lngX, lngY), RGB(intS, intS, intS)
' 影像的寬度
Next lngX
' 影像的高度
Next lngY
End Sub
JAVA with NetBeans v8.1¶
import java.awt.FileDialog;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.awt.image.DataBufferByte;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
FileDialog f = new FileDialog(this, "Open File", FileDialog.LOAD);
// 設定檔案開啟對話框的初始目錄
f.setDirectory(".");
// 顯示檔案對話框,並等待使用者操作
f.show();
// 紀錄檔案目錄字串
String directory = f.getDirectory();
// 建立檔案路徑及名稱的字串
String filepath = directory+f.getFile();
// 宣告 BufferedImage 物件
BufferedImage img = null;
try {
// 經由檔案路徑及名稱讀取圖檔
img = ImageIO.read(new File(filepath));
// 準備二值化
int[][] result = convertToBinarization(img);
// 顯示二值化影像
jLabel1.setIcon(new javax.swing.ImageIcon(img));
}
// 如果出現例外,則顯示錯誤訊息
catch (IOException e) {
System.err.println("I could not load the file \'"+directory+"'. Sorry.");
}
}
// RGB影像二值化的函式
private static int[][] convertToBinarization(BufferedImage image) {
// 獲得影像的寬度
int width = image.getWidth();
// 獲得影像的高度
int height = image.getHeight();
// 建立二維陣列紀錄影像像素資料
int[][] result = new int[height][width];
// 影像的高度
for (int row = 0; row < height; row++) {
// 影像的寬度
for (int col = 0; col < width; col++) {
// 獲得RGB值
result[row][col] = image.getRGB(row, col);
// 獲得整數的RGB值
int iRet = result[row][col];
// 宣告透明度(alpha)變數
int iA = 0;
// 宣告紅色變數
int iR = 0;
// 宣告綠色變數
int iG = 0;
// 宣告藍色變數
int iB = 0;
int iGray = 0;
// 獲得透明度值
iA = (((int) iRet & 0xff) << 24);
// 獲得藍色值
iB = ((int) iRet & 0xff);
// 獲得綠色值
iG = (((int) iRet & 0x00ff00) >> 8);
// 獲得紅色值
iR = (((int) iRet & 0xff0000) >> 16);
// RGB轉換為灰階
iG = ( iR + iG + iB ) / 3;
// 灰階值大於門檻值
if ( iG > 120 )
{
// 設定為白色
iRet = 0xffffff;
// 寫入白色值到影像中
image.setRGB(row, col, iRet);
}
else
{
// 寫入黑色值到影像中
image.setRGB(row, col, 0);
}
}
}
// 回傳處理結果值
return result;
}
DELPHI XE5¶
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtDlgs, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
OpenPictureDialog1: TOpenPictureDialog;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
// 宣告檔名字串
Str : String;
implementation
{$R *.dfm}
procedure TForm1.Button2Click(Sender: TObject);
var
PByte :PByteArray;
Gray,x,y :Integer;
ImageBmp :TBitmap;
begin
// 如果檔名字串為空白,則顯示錯誤訊息
if Str = '' then
showmessage('Can not open this file, because it is an empty.')
// 反之,有檔名則繼續處理
else
begin
// 建立一個TBitmap object.
ImageBmp :=TBitmap.Create;
// 儲存開啟的圖檔資料
ImageBmp.Assign(Image1.Picture.Bitmap);
// 設定影像格式為 24 bits
ImageBmp.PixelFormat :=pf24Bit;
// 影像的高度
for y:=0 to ImageBmp.Height-1 do
begin
// 設定Y軸掃描線
PByte := ImageBmp.scanline[y];
// 影像的寬度
for x:=0 to ImageBmp.Width-1 do
begin
// 四捨五入轉換RGB為YUV的Y(灰階)
Gray:=Round(PByte[x*3+2]*0.3+PByte[x*3+1]*0.59+PByte[x*3]*0.11);
// 當灰階值大於門檻值
if Gray > 120 then
// 設定為白色
begin
PByte[x*3]:=255;
PByte[x*3+1]:=255;
PByte[x*3+2]:=255;
end
// 反之,則為黑色
else
begin
PByte[x*3]:=0;
PByte[x*3+1]:=0;
PByte[x*3+2]:=0;
end
end;
end;
// 影像框儲存處理後的影像
Image1.Picture.Bitmap.Assign(ImageBmp);
// 釋放 TBitmap object 的記憶體
ImageBmp.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
// 宣告完整路徑的字串
Path:string;
begin
// 記錄路徑為應用程式的路徑
path:=ExtractFilePath(application.ExeName);
// 設定圖形開啟對話框的初始路徑
OpenPictureDialog1.InitialDir := Path;
// 顯示圖形開啟對話框
if OpenPictureDialog1.Execute then
begin
// 記錄圖形開啟對話框的檔案名稱
Str := OpenPictureDialog1.FileName;
// 藉由檔案名稱載入圖檔
Image1.Picture.LoadFromFile(Str);
end;
end;
end.
Android v4.1.2 with Eclipse¶
package com.example.binarization.camera;
import com.example.binarization.camera.R;
import android.os.Bundle;
import android.app.Activity;
import android.view.*;
import android.widget.*;
import android.annotation.SuppressLint;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
@SuppressLint("NewApi")
public class MainActivity extends Activity implements SurfaceHolder.Callback {
SurfaceView mSurfaceView ;
Button btn_Capture;
Camera mCamera;
PictureCallback mPictureCB;
AutoFocusCallback mAutoFocusCB;
ImageView ImgView;
TextView txtView;
Bitmap bitmapClone;
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 設定視窗的像素格式為允許透明值(alpha)
// 設定這個數值會覆寫掉原來系統預設值
getWindow().setFormat(PixelFormat.TRANSLUCENT);
// 設定視窗特徵為沒有標題
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 設定視窗版型為全螢幕
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 藉由資源類別(R)設定視窗的版型
setContentView(R.layout.activity_main);
// 設定視窗的方向
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// 設定元件
ImgView = (ImageView)this.findViewById(R.id.ImgView);
txtView = (TextView)this.findViewById(R.id.txtView);
btn_Capture = (Button)this.findViewById(R.id.btn_Capture);
mSurfaceView = (SurfaceView)this.findViewById(R.id.surView_Camera);
// 宣告並獲得 SurfaceHolder,這允許控制或改變像素
SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// 建立拍照的回呼函式
mPictureCB = new PictureCallback(){
// 開始二值化
// 覆寫 onPictureTaken 函式.
@Override
public void onPictureTaken(byte[] data, Camera camera){
// BitmapFactory 可以解碼RAW資料為BMP格式
Bitmap mBitmap = BitmapFactory.decodeByteArray(data, 0 , data.length);
bitmapClone = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig());
bitmapClone.copy(mBitmap.getConfig(), true);
int iY = 0;
int iX = 0;
int iPixel = 0;
int iRed = 0;
int iGreen = 0;
int iBlue = 0;
int iRGBAvg = 0;
// 灰階影像處理轉黑白影像
// 影像的高度
for ( iY = 0; iY < bitmapClone.getHeight(); iY++ )
{
// 影像的寬度
for ( iX = 0; iX < bitmapClone.getWidth(); iX++ )
{
// 獲得像素值
iPixel = mBitmap.getPixel(iX, iY);
// 獲得紅色像素
iRed = Color.red(iPixel);
// 獲得綠色像素
iGreen = Color.green(iPixel);
// 獲得藍色像素
iBlue = Color.blue(iPixel);
// 計算灰階值
iRGBAvg = ( iRed + iGreen + iBlue ) / 3;
// 當灰階值大於門檻值
if ( iRGBAvg > 120 )
{
// 設定像素為白色
bitmapClone.setPixel(iX, iY, Color.rgb(255, 255, 255));
}
else
{
// 設定像素為黑色
bitmapClone.setPixel(iX, iY, Color.rgb(0, 0, 0));
}
}
}
// 設定顯示處理過的影像
ImgView.setImageBitmap(bitmapClone);
// 攝影機啟動預覽
camera.startPreview();
// 關閉自動對焦回呼函式
camera.autoFocus(null);
}
};
// 建立自動對焦回呼函式
mAutoFocusCB = new AutoFocusCallback(){
@Override
public void onAutoFocus(boolean success, Camera camera){
// 當對焦成功時,才執行拍照功能
if ( success == true )
{
// 進入拍照回呼函式
camera.takePicture(null, null, mPictureCB);
}
}
};
// 當使用者按下拍照鈕,開啟自動對焦回呼函式
btn_Capture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
// 確認攝影機有開啟
if(mCamera != null){
// 建立一個執行緒
new Thread(new Runnable() {
public void run() {
// 執行自動對焦
mCamera.autoFocus(mAutoFocusCB);
}
}).start();
}
}catch(Exception e) {
e.printStackTrace();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// 獲得相機參數
Camera.Parameters parameters = mCamera.getParameters();
// 設定影像大小
parameters.setPictureSize(640, 480);
// 設定預覽大小
parameters.setPreviewSize(width, height);
// 設定自動對焦
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// 將參數寫入相機
mCamera.setParameters(parameters);
// 開始預覽
mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 如果相機初始化成功就開啟相機
if ( mCamera == null )
{
mCamera = Camera.open();
}
try {
// 設定 SurfaceHolder.
mCamera.setPreviewDisplay(holder);
}catch(Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// 停止預覽
mCamera.stopPreview();
// 釋放相機
mCamera.release();
}
}
HTML5 + Javascript¶
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function imageLoaded(ev) {
element = document.getElementById("cancan");
c = element.getContext("2d");
// 這張影像解析度為 512x512
im = ev.target;
// 讀取影像元素的寬與高
width = element.width;
height = element.height;
// 設定左邊 canvas 的位置
c.drawImage(im, 0, 0);
// 獲得左邊 canvas 的像素資料
imageData = c.getImageData(0, 0, width, height);
// 右邊 canvas 的X軸起始位置
w2 = width / 2;
// 開始二值化
// 影像的高度
for (y = 0; y < height; y++) {
// 每一個像素值為 32 bits
// 設定Y軸索引值
inpos = y * width * 4;
// 設定輸出索引值
outpos = inpos + w2 * 4
// 影像的寬度
for (x = 0; x < w2; x++) {
// 取得紅色像素
r = imageData.data[inpos++]
// 取得綠色像素
g = imageData.data[inpos++]
// 取得藍色像素
b = imageData.data[inpos++]
// 取得透明值
a = imageData.data[inpos++]
// RGB轉換YUV的Y(灰階)
gray = (0.299 * r + 0.587 * g + 0.114 * b)
// 若灰階值大於門檻值
if ( gray > 120 )
{
// 設定輸出像素為白色
imageData.data[outpos++] = 255;
imageData.data[outpos++] = 255;
imageData.data[outpos++] = 255;
imageData.data[outpos++] = a;
}
else
{
// 設定輸出像素為黑色
imageData.data[outpos++] = 0;
imageData.data[outpos++] = 0;
imageData.data[outpos++] = 0;
imageData.data[outpos++] = a;
}
} // 影像的寬度
} // 影像的高度
// 將影像資料繪製在 canvas.
c.putImageData(imageData, 0, 0);
}
// 建立影像物件.
im = new Image();
// 設定JavaScript的函式
im.onload = imageLoaded;
// 這張影像的解析度是 512x512.
im.src = "B_01.jpg";
</script>
</head>
<body>
<!—建立一個 canvas -->
<canvas id="cancan" width="1024", height="512">Canvas</canvas>
</body>
</html>
Matlab 2011¶
% 載入影像
x=imread('B_01.bmp');
% RGB轉換為灰階
gray=rgb2gray(x);
% 二值化
BW=im2bw(x);
% 顯示影像
imshow(BW);