You are on page 1of 17

Face tracking :

Chức năng theo dõi khuôn mặt có nghĩa là camera sẽ tự động


chụp khung hình để thấy và theo dõi khuôn mặt của mọi người
đang vào khu vực mà camera quan-sát thấy, chỉ tự động chụp
hình và lưu lại các khuôn mặt vào thẻ nhớ SD.

Cascade Classifiers
Quá trình nhận dạng đối tượng (trong trường hợp của chúng ta,
khuôn mặt) thường hiệu quả nếu dựa trên các tính năng tiếp
quản bao gồm thông tin bổ sung về lớp đối tượng sẽ được tiếp
quản. Trong hướng dẫn này, chúng ta sẽ sử dụng các tính năng
giống Haar và Mô hình nhị phân cục bộ (LBP) để mã hóa các
tương phản được làm nổi bật bởi khuôn mặt người và các mối
quan hệ không gian của nó với các đối tượng khác có trong
hình. Thông thường các tính năng này được trích xuất bằng
Trình phân loại Cascade phải được đào tạo để nhận biết với các
đối tượng khác nhau chính xác: phân loại của khuôn mặt sẽ
khác nhiều so với phân loại của xe hơi.
Bắt đầu
Hãy tạo một dự án JavaFX mới. Trong Trình tạo cảnh, đặt phần
tử cửa sổ để chúng ta có Đường viền với:

 trên TOP một VBox một HBox và một dấu phân cách. Trong
HBox, chúng tôi đang cần phải có hai hộp kiểm, cái đầu tiên
là chọn Bộ phân loại Haar và cái thứ hai là chọn Bộ phân loại
LBP.
 trên TOP một VBox một HBox và một dấu phân cách. Trong
HBox, chúng tôi đang cần phải có hai hộp kiểm, cái đầu
tiên là chọn Bộ phân loại Haar và cái thứ hai là chọn Bộ
phân loại LBP.
 <CheckBox fx: id = "haarClassifier" onAction =
"#haarSelected" text = "Haar Classifier" />
 <CheckBox fx: id = "lbpClassifier" onAction =
"#lbpSelected" text = "LBP Classifier" />
 trong TRUNG TÂM, chúng tôi sẽ đặt ImageView cho luồng
web cam.
 <ImageView fx: id = "originalFrame" />
 trên BOTTOM, chúng ta có thể thêm nút thông thường để
bắt đầu / dừng luồng
 <Nút fx: id = "cameraButton" căn chỉnh = "centre" text
= "Camera khởi động" onAction = "#startCamera" vô
hiệu hóa = "đúng" />
Gui sẽ trông giống như thế này:
Tải Classifiers
Trước hết chúng ta cần thêm một thư mục resource vào dự án
của chúng tôi và đặt các phân loại vào đó. Để sử dụng các trình
phân loại, chúng ta cần tải chúng từ thư mục tài nguyên, vì vậy
mỗi lần chúng ta kiểm tra một trong hai hộp kiểm, chúng ta sẽ
tải đúng trình phân loại. Để làm như vậy, hãy thực hiện
các OnAction phương thức mà chúng ta đã khai báo trước đó:

 haarSelected
bên trong phương thức này, chúng ta sẽ tải Trình phân loại
Haar bị mất (ví dụ haarcascade_frontalface.xml ) như sau:
này . checkboxSelection ( "tài nguyên / lbpcascades /
lbpcascade_frontalface_alt.xml" );
...
tin trống checkboxSelection ( Chuỗi ... classifierPath )
{
// nạp phân loại (s)
cho ( Chuỗi xmlClassifier : classifierPath )
{
này . mặtCascade . tải ( xmlClassifier );
}

// bây giờ việc chụp có thể bắt đầu


điều này . cameraButton . setDisable ( sai );
}
 lbpSelected
đối với LPB, chúng ta có thể sử dụng cùng một phương
thức và thay đổi đường dẫn của trình phân loại sẽ được tải:
này . hộp kiểm chọn ( "resource / lbpcascades /
lbpcascade_frontalface.xml" );
Phát hiện và theo dõi
Khi chúng tôi đã tải các trình phân loại, chúng tôi sẵn sàng bắt
đầu phát hiện; chúng ta sẽ thực hiện phát hiện
trong detectAndDisplay phương thức. Trước hết chúng ta cần
chuyển đổi khung theo thang độ xám và cân bằng biểu đồ để
cải thiện kết quả:

Imgproc . cvtColor ( khung , khung xám , Imgproc .


COLOR_BGR2GRAY );
Imgproc . equalizeHist ( grayFrame , grayFrame );
Sau đó, chúng ta phải đặt kích thước tối thiểu của khuôn mặt
được phát hiện (yêu cầu này là cần thiết trong chức năng phát
hiện thực tế). Hãy đặt kích thước tối thiểu là 20% của khung
hình:

nếu ( này . absoluteFaceSize == 0 )


{
int height = grayFrame . hàng ();
if ( Math . round ( height * 0.2f ) > 0 )
{
this . perfectFaceSize = Toán . vòng ( chiều cao * 0,2f
);
}
}
Bây giờ chúng ta có thể bắt đầu phát hiện:

này . mặtCascade . detectMultiScale ( grayFrame , phải đối


mặt , 1.1 , 2 , 0 | Objdetect . CASCADE_SCALE_IMAGE , mới
Kích ( này . absoluteFaceSize , này . absoluteFaceSize ), mới
Kích ());
Các detectMultiScale chức năng phát hiện đối tượng có kích
thước khác nhau trong hình ảnh đầu vào. Các đối tượng được
phát hiện được trả về dưới dạng danh sách các hình chữ
nhật. Các tham số là:

 Ma trận hình ảnh loại CV_8U chứa hình ảnh nơi phát hiện
đối tượng.

 đối tượng Vector hình chữ nhật trong đó mỗi hình chữ
nhật chứa đối tượng được phát hiện.

 scaleFactor Parameter chỉ định giảm kích thước hình ảnh


ở mỗi tỷ lệ hình ảnh.

 minNeighbor Tham số chỉ định có bao nhiêu hàng xóm


mỗi hình chữ nhật ứng cử viên phải giữ lại nó.

 cờ Tham số có cùng ý nghĩa đối với một tầng cũ như trong


hàm cvHaarDetectObjects. Nó không được sử dụng cho một
tầng mới.

 minSize Kích thước đối tượng tối thiểu có thể. Các đối
tượng nhỏ hơn đó được bỏ qua.

 maxSize Kích thước đối tượng tối đa có thể. Các đối tượng
lớn hơn đó được bỏ qua.

Vì vậy, kết quả của việc phát hiện sẽ nằm trong tham số đối
tượng hoặc trong trường hợp của chúng ta faces .

Chúng ta hãy đặt kết quả này vào một mảng Rects và vẽ chúng
lên khung, bằng cách làm như vậy chúng ta có thể hiển thị
khuôn mặt được phát hiện là:

Rect [] FacArray = khuôn mặt . toArray ();


for ( int i = 0 ; i < FacArray . length ; i ++)
Core . hình chữ nhật ( khung , faceArray [ i ]. tl (), FacArray [
i ]. br (), new Scalar ( 0 , 255 , 0 , 255 ), 3 );
Như bạn có thể thấy, chúng tôi đã chọn màu xanh lục với nền
ba màu : . và đứng cho phía trên bên trái và dưới cùng bên
phải và chúng đại diện cho hai đỉnh đối diện. Tham số cuối
cùng chỉ đặt độ dày của đường viền hình chữ
nhật. Scalar(0, 255, 0, 255).tl().br()

Phần theo dõi có thể được thực hiện bằng cách


gọi detectAndDisplay phương thức cho mỗi khung.
Source Code

 FaceDetection.java

lớp công khai FaceDetection mở rộng Ứng dụng {


@Override
public void start ( Giai đoạn sơ cấp )
{
thử
{
// tải tài nguyên
FXML FXMLLoader loader = new FXMLLoader (
getClass (). getResource ( "FD_FX.fxml" ));
BorderPane gốc = ( BorderPane ) loader . tải ();
// đặt
gốc nền whitesmoke . setStyle ("-fx-nền-màu:
whitesmoke;" );
// tạo và định kiểu một cảnh
Cảnh cảnh = new Cảnh ( root , 800 , 600 );
cảnh . getStylesheets (). thêm ( getClass ().
getResource ( "application.css" ). toExternalForm ());
// tạo giai đoạn với tiêu đề đã cho và
// cảnh
sơ cấp được tạo trước đó . setTitle ( "Nhận diện
khuôn mặt" );
sơ cấp . setScene (cảnh );
// hiển thị GUI
primaryStage . hiển thị ();

// init bộ điều khiển


FD_Cont điều khiển = loader . getControll ();
bộ điều khiển . init ();
}
bắt ( Ngoại lệ e )
{
e . printStackTrace ();
}
}

public static void main ( String [] args )


{
// tải
hệ thống thư viện OpenCV riêng . LoadLibrary ( lõi .
NATIVE_LIBRARY_NAME );

khởi động ( args );


}
}

 FD_Controll.java <https://github.com/java-opencv/Polito-
Java-OpenCV-Tutorials-Source-Code/blob/master/Face
%20Detection/src/application/FD_Controll.java>

công lớp FD_Controller {


// nút FXML
@FXML
tin Nút cameraButton ;
// khu vực FXML cho thấy sự hiện khung
@FXML
tin ImageView originalFrame ;
// hộp kiểm để chọn Haar Classifier
@FXML
private CheckBox haarClassifier ;
// hộp kiểm để chọn Trình phân loại LBP
@FXML
private CheckBox lbpClassifier ;

// bộ hẹn giờ để có được


bộ đếm thời gian riêng tư Bộ đếm thời gian ;
// đối tượng OpenCV mà thực hiện việc quay video
riêng VideoCapture chụp ;
// một cờ để thay đổi hành vi nút
riêng boolean cameraActive ;
// đối tượng phân loại tầng mặt
riêng CascadeClassifier faceCascade ;
// kích thước mặt tối thiểu
riêng int absoluteFaceSize ;
hình ảnh riêng tư CamStream ;

/ **
* Khởi tạo các biến điều khiển
*/
được bảo vệ void init ()
{
this . chụp = VideoCapture mới (); này . faceCascade
= new CascadeClassifier (); này . perfectFaceSize = 0 ; }

/ **
* Hành động kích hoạt bằng cách đẩy nút trên GUI
*/
@FXML
bảo vệ khoảng trống startCamera ()
{
nếu (! Này . CameraActive )
{
// vô hiệu hóa thiết lập hộp kiểm
này . Máy đo độ phân giải . setDisable ( đúng );
này . Máy phân tích lbp . setDisable ( đúng );

// bắt đầu quay video


này . chụp . mở ( 0 );

// là luồng video có sẵn?


if ( this . Capture . isOpened ())
{
this . cameraActive = true ;

// lấy một khung hình cứ sau 33 ms (30 khung


hình / giây)
TimerTask frameGrabber = new TimerTask
() {
@Override
public void run ()
{
CamStream = GrabFrame ();
Nền tảng . runLater ( new Runnable
() {
@Override
public void run () {

// hiển thị các khung


ban đầu gốcFrame .
setImage ( CamStream );
// thiết lập cố định chiều
rộng
originalFrame .
setFitWidth ( 600 );
// gìn giữ tỷ lệ hình ảnh
originalFrame .
setPreserveRatio ( đúng );

}
});
}
};
này . hẹn giờ = Timer mới (); này . hẹn giờ .
lịch trình ( frameGrabber , 0 , 33 );
// cập nhật nội dung nút
này . cameraButton . setText ( "Dừng camera"
);
}
other
{
// đăng nhập
hệ thống lỗi . err . println ( "Không thể mở kết
nối camera ..." );
}
}
khác
{
// máy ảnh không hoạt động tại thời điểm
này . cameraActive = false ;
// cập nhật lại nội dung nút
này . cameraButton . setText ( "Camera khởi động"
);
// cho phép thiết lập các hộp kiểm
này . Máy đo độ phân giải . setDisable ( sai );
này . Máy phân tích lbp . setDisable ( sai );

// dừng bộ đếm thời gian


if ( this . timer ! = null )
{
this . hẹn giờ . hủy bỏ ();
này . bộ đếm thời gian = null ;
}
// phát hành máy ảnh
này . chụp . phát hành ();
// làm sạch vùng ảnh
gốcFrame . setImage ( null );
}
}

/ **
* Nhận khung từ luồng video đã mở (nếu có)
*
* @return {@link Image} để hiển thị
*/
private Image GrabFrame ()
{
// init mọi thứ
Image imageToShow = null ;
Khung Mat = Mat mới ();

// kiểm tra xem bản chụp có mở


không nếu ( this . Capture . isOpened ())
{
thử
{
// đọc khung hiện tại
này . chụp . đọc ( khung );

// nếu khung không trống, xử lý nó


nếu (! frame . blank ())
{
// phát hiện khuôn mặt
này . phát hiệnAndDisplay ( khung );

// chuyển đổi đối tượng Mat (OpenCV)


thành Image (JavaFX)
imageToShow = mat2Image ( frame );
}

}
Catch ( Exception e )
{
// đăng nhập
hệ thống lỗi (đầy đủ) . err . in ( "LRI" );
e . printStackTrace ();
}
}

trả lại hình ảnh ToShow ;


}

/ **
* Thực hiện phát hiện khuôn mặt và hiển thị hình chữ nhật
xung quanh khuôn mặt được phát hiện.
*
* @param frame
*
khung hiện tại */
private void DetAndDisplay ( Khung Mat ) { // init
MatOfRect face = new MatOfRect (); Mat GrayFrame = new Mat
();

// chuyển đổi khung theo thang màu xám


Imgproc . cvtColor ( khung , khung xám , Imgproc .
COLOR_BGR2GRAY );
// cân bằng biểu đồ khung để cải thiện kết quả
Imgproc . equalizeHist ( grayFrame , grayFrame );

// tính toán kích thước mặt tối thiểu (20% chiều cao
khung)
nếu ( này . AbsoluteFaceSize == 0 )
{
int height = grayFrame . hàng ();
if ( Math . round ( height * 0.2f ) > 0 )
{
this . perfectFaceSize = Toán . vòng ( chiều
cao * 0,2f );
}
}

// phát hiện phải đối mặt với


điều này . mặtCascade . detectMultiScale ( grayFrame ,
phải đối mặt , 1.1 , 2 , 0 | Objdetect .
CASCADE_SCALE_IMAGE , mới Kích (
này . absoluteFaceSize , này .
absoluteFaceSize ), mới Kích ());

// mỗi hình chữ nhật trong các mặt là một mặt


Rect [] FacArray = các mặt . toArray ();
for ( int i = 0 ; i < FacArray . length ; i ++)
Core . hình chữ nhật ( khung , FacArray [ i ]. tl (),
FacArray [ i ]. br (), new Scalar ( 0 , 255 , 0 , 255), 3 );

/ **
* Khi hộp kiểm Haar được chọn, bỏ chọn cái khác và tải
* trình phân loại XML thích hợp
*
*/
@FXML
được bảo vệ void haarSelected ()
{
// kiểm tra xem hộp kiểm lpb có được chọn không và bỏ
chọn
nếu ( này . LppClassifier . được chọn ())
này . Máy phân tích lbp . setSelected ( false );

này . hộp kiểmSelection ( "resource / haarcascades /


haarcascade_frontalface_alt.xml" );
}

/ **
*
Khi hộp kiểm LBP được chọn, bỏ chọn cái khác và tải
* trình phân loại XML thích hợp
*/
@FXML
được bảo vệ void lbpSelected ()
{
// kiểm tra xem hộp kiểm haar có được chọn không và
bỏ chọn
nếu ( này . HaarClassifier . được chọn ())
này . Máy đo độ phân giải . setSelected ( false );

này . hộp kiểm chọn ( "resource / lbpcascades /


lbpcascade_frontalface.xml" );
}

/ **
* Hoạt động chung cho cả hai lựa chọn hộp kiểm
*
* @param classifierPath
* đường dẫn tuyệt đối trong đó tệp XML đại diện cho một
khóa đào tạo
* được đặt cho một trình phân loại hiện diện
*/
private void boxSelection ( String ... classifierPath )
{
// tải (các) bộ phân loại
cho ( Chuỗi xmlClassifier : classifierPath )
{
this . mặtCascade . tải ( xmlClassifier );
}

// bây giờ việc chụp có thể bắt đầu


điều này . cameraButton . setDisable ( sai );
}

/ **
* Chuyển đổi một đối tượng Mat (OpenCV) trong Hình ảnh
tương ứng cho JavaFX
*
* @param khung
* {@link Mat} đại diện cho khung hiện tại
* @return {@link Image} để hiển thị
*/
private Image mat2Image ( mat khung )
{
// tạo một tạm thời đệm
MatOfByte đệm = mới MatOfByte ();
// mã hóa khung hình trong bộ đệm, theo định dạng
PNG
Highgui . imencode ( ".png" , khung , bộ đệm );
// xây dựng và gửi lại một hình ảnh được tạo ra từ các
hình ảnh được mã hóa trong
// đệm
trở lại mới hình ảnh ( mới ByteArrayInputStream ( đệm
. ToArray ()));
}
}

 FD_FX.fxml

<BorderPane xmlns: fx = "http://javafx.com/fxml/1" fx:


controller = "application.FD_Contoder" >
<top>
<VBox>
<HBox canh = "TRUNG TÂM" spaces = "10" >
<padding >
<Insets top = "10" bottom = "10" />
</ padding>
<CheckBox fx: id = "haarClassifier" onAction
= "#haarSelected" text = "Haar Classifier" />
<CheckBox fx: id = "lbpClass " onAction =
"#lbpSelected" text = "Trình phân loại LBP" />
</ HBox>
<Dấu phân cách />
</ VBox>
</ top>
<centre>
<VBox căn chỉnh = "TRUNG TÂM" >
<padding>
<Insets right = "10" left = "10" />
</ padding>
<ImageView fx: id = "originalFrame" />
</ VBox>
</ centre>
<bottom>
<HBox căn chỉnh = "TRUNG TÂM" >
<padding>
<Insets top = "25" right = "25" bottom =
"25" left = "25" />
</ padding>
<Nút fx: id = "cameraButton" căn chỉnh
="centre" text = "Camera khởi động" onAction =
"#startCamera" vô hiệu hóa = "true" />
</ HBox>
</ bottom>
</ BorderPane>

You might also like