點擊上方藍字關注我哦~
01
前言
最近筆者在一些項目上需要對圖像做些變換操作,這些操作opencv基本上都幫我們實現(xiàn)了,但是在linux系統(tǒng)和Android系統(tǒng)實現(xiàn)起來還是有些區(qū)別的,在這里和大家分享下。
02
知識點
由四對點計算透射變換
函數(shù)原型:
CvMat* cvGetPerspectiveTransform( const CvPoint2D32f*src, const CvPoint2D32f* dst,
CvMat*map_matrix );
參數(shù)含義:
src:輸入圖像的四邊形頂點坐標。
dst:輸出圖像的相應的四邊形頂點坐標。
map_matrix:指向3×3輸出矩陣的指針。
函數(shù)cvGetPerspectiveTransform計算滿足以下關系的透射變換矩陣:
這里,dst(i)= (x'i,y'i),src(i)= (xi,yi),i = 0..3。
對圖像進行透視變換
函數(shù)原型:
void cvWarpPerspective( const CvArr* src, CvArr* dst,const CvMat* map_matrix,
int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,
CvScalar fillval=cvScalarAll(0) );
src:輸入圖像.
dst:輸出圖像.
map_matrix:3×3 變換矩陣
flags:插值方法和以下開關選項的組合:
· CV_WARP_FILL_OUTLIERS- 填充所有縮小圖像的像素。如果部分象素落在輸入圖像的邊界外,那么它們的值設定為 fillval.
· CV_WARP_INVERSE_MAP- 指定 matrix 是輸出圖像到輸入圖像的反變換,因此可以直接用來做象素插值。否則, 函數(shù)從 map_matrix 得到反變換。
fillval:用來填充邊界外面的值。
函數(shù) cvWarpPerspective 利用下面指定矩陣變換輸入圖像:
如果沒有指定 CV_WARP_INVERSE_MAP:
否則:
要變換稀疏矩陣,使用 cxcore 中的函數(shù) cvTransform。
03
樹莓派實現(xiàn)
using namespace std;
using namespace cv;
int main()
{
Point2f Ceneter(640, 512);// 1-5;在圖片上確定5個矯正點 坐標參數(shù)可調(diào)整 圖片默認size;1280*1024
Point2f left_up(485, 510);
Point2f right_up(840, 425);
Point2f right_down(847, 510);
Point2f left_down(487, 567);
const Point2f src[4] = { left_up, right_up, right_down, left_down }; //6;4個坐標數(shù)組(上下左右4個坐標)
float half_H = 42; //圖片高度調(diào)整范圍
float half_W = 280; //圖片寬度調(diào)整范圍
float scale = 0.8; //調(diào)整系數(shù)
float new_half_H = half_H * scale;//同7
float new_half_W = half_W * scale;//同8
float shift_x =100;//rng.uniform(50.f, 100.f);//新坐標x軸調(diào)整參數(shù)
float shift_y = -20; //新坐標y軸調(diào)整參數(shù)
Point2f left_upX(Ceneter.x + shift_x - new_half_W, Ceneter.y + shift_y - new_half_H);//14-17;生成上下左右4個新坐標
Point2f right_upX(Ceneter.x + shift_x + new_half_W, Ceneter.y + shift_y - new_half_H);
Point2f right_downX(Ceneter.x + shift_x + new_half_W, Ceneter.y + shift_y + new_half_H);
Point2f left_downX(Ceneter.x + shift_x - new_half_W, Ceneter.y + shift_y + new_half_H);
Mat perspectivemat;
const Point2f dst[4] = { left_upX, right_upX, right_downX, left_downX };//
Mat TransMat = getPerspectiveTransform(src, dst);
Mat Transimg; //新圖片矩陣
//Shape shape(1, 3, 720, 1280);
int Train_Channel_size_ = 3;//shape.C;
Mat handimg = cv::imread("B.jpg");
//cv::Mat& handimg = cv::imread("./000001.jpg", -1);
if (!handimg.data) {
// return 0;
}
//std::vector<ResultBox> one_img_bboxes_target;
Size img_size;
//Get_Boxes_Info(image_path + ".xml", one_img_bboxes_target, img_size);
Mat image_reclor;
if (handimg.channels() == 3 && Train_Channel_size_ == 1)
cvtColor(handimg, image_reclor, cv::COLOR_BGR2GRAY);
else if (handimg.channels() == 4 && Train_Channel_size_ == 1)
cvtColor(handimg, image_reclor, cv::COLOR_BGRA2GRAY);
else if (handimg.channels() == 4 && Train_Channel_size_ == 3)
cvtColor(handimg, image_reclor, cv::COLOR_BGRA2BGR);
else if (handimg.channels() == 1 && Train_Channel_size_ == 3)
cvtColor(handimg, image_reclor, cv::COLOR_GRAY2BGR);
else
image_reclor = handimg;
cv::Mat img_resize;
if (image_reclor.size() != cv::Size(1280, 720)) {
resize(image_reclor, img_resize, cv::Size(1280, 720));
}
else
{
img_resize = image_reclor;
}
warpPerspective(img_resize, Transimg, TransMat, img_resize.size());
imwrite("Transimg.jpg", Transimg);
cv::waitKey(0);
return 0;
}
04
安卓端實現(xiàn)
private Point Ceneter = new Point(640, 512);
private float half_H = 42;
private float half_W = 280;
private float scale = (float) 0.8;
private float shift_x =100;
private float shift_y = -20;
private Mat TransMat;
private void init(){
Mat src_mat = new Mat(4,1,CvType.CV_32FC2);
Mat dst_mat = new Mat(4,1,CvType.CV_32FC2);
src_mat.put(0,0,
485, 510,
840, 425,
847, 510,
487, 567);
float new_half_H = half_H * scale;
float new_half_W = half_W * scale;
dst_mat.put(0,0,
Ceneter.x + shift_x - new_half_W, Ceneter.y + shift_y - new_half_H,
Ceneter.x + shift_x + new_half_W, Ceneter.y + shift_y - new_half_H,
Ceneter.x + shift_x + new_half_W, Ceneter.y + shift_y + new_half_H,
Ceneter.x + shift_x - new_half_W, Ceneter.y + shift_y + new_half_H);
TransMat = Imgproc.getPerspectiveTransform(src_mat, dst_mat);
}
private void prosessImg(Bitmap frame, String resultFileName){
Bitmap rgba = frame.copy(Bitmap.Config.ARGB_8888, true);
Mat handimg = new Mat();// = imread(image_path, 1);
Utils.bitmapToMat(rgba, handimg);
int Train_Channel_size_ = 3;
Mat image_reclor = new Mat();
if (handimg.channels() == 3 && Train_Channel_size_ == 1)
cvtColor(handimg, image_reclor, COLOR_BGR2GRAY);
else if (handimg.channels() == 4 && Train_Channel_size_ == 1)
cvtColor(handimg, image_reclor, COLOR_BGRA2GRAY);
else if (handimg.channels() == 4 && Train_Channel_size_ == 3)
cvtColor(handimg, image_reclor, COLOR_BGRA2BGR);
else if (handimg.channels() == 1 && Train_Channel_size_ == 3)
cvtColor(handimg, image_reclor, COLOR_GRAY2BGR);
else
image_reclor = handimg;
Mat img_resize = new Mat();
Size size = new Size(1280, 720);
if (image_reclor.size() != size) {
Imgproc.resize(image_reclor, img_resize, size);
}
else
{
img_resize = image_reclor;
}
Mat Transimg = new Mat();
Imgproc.warpPerspective(img_resize, Transimg, TransMat, img_resize.size());
rgba = PhotoUtil.matToBitmap(Transimg);
String resultPicName = resultFileName.substring(0, resultFileName.lastIndexOf(".txt"));
resultPicName = resultPicName + "_res.jpg";
FileUtil.saveBitmap(new File(resultPicName),rgba);
rgba.recycle();
rgba = null;
}
05
結果
原圖
變化后圖像
/ The End /
掃碼關注我們
看更多嵌入式案例
喜歡本篇內(nèi)容請給我們點個在看
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!