3atv精品不卡视频,97人人超碰国产精品最新,中文字幕av一区二区三区人妻少妇,久久久精品波多野结衣,日韩一区二区三区精品

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

opencv图像处理总结

發(fā)布時間:2025/4/14 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 opencv图像处理总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

opencv圖像處理基本操作



1. 矩陣數(shù)據(jù)類型
通用矩陣數(shù)據(jù)類型:
CV_<bit_depth>(S|U|F)C<number_of_channels>
其中,S表示帶符號整數(shù);
U表示無符號整數(shù);
F表示浮點數(shù);
例如:CV_8UC1 表示8位無符號單通道矩陣;
   CV_32FC2 表示32位浮點數(shù)雙通道矩陣;


2. 圖像數(shù)據(jù)類型
通用圖像數(shù)據(jù)類型為:
   IPL_DEPTH_<bit_depth>(S|U|F)
如:IPL_DEPTH_8U 表示8位無符號整數(shù)圖像;
  IPL_DEPTH_32F 表示32位浮點數(shù)圖像;


3. 分配和釋放圖像
3.1 分配一幅圖像
  IpIImage * cvCreateImage(cvSize size, int depth, int channels);
其中size可以用cvSize(width, height)得到。
depth為像素的單位,包括:
IPL_DEPTH_8U
IPL_DEPTH_8S
IPL_DEPTH_16U
IPL_DEPTH_16S
IPL_DEPTH_32S
IPL_DEPTH_32F
IPL_DEPTH_64F
channels為每個像素的通道數(shù),可以是1,2,3或4。通道是交叉排列的,一幅彩色
圖像的通常的排列順序是:
b0 g0 r0 b1 g1 r1 ...


例如:分配一個單通道單字節(jié)圖像的語句是:
IpIImage* img1 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);


分配一個三通道浮點數(shù)圖像語句是:
IpIImage* img2 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_32F, 3);


3.2 釋放圖像
void cvReleaseImage(IpIImage **);


3.3 復(fù)制一幅圖像
IpIImage* cvCloneImage(IpIImage *);
如:
IpIImage* img1 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 1);
IpIImage* img2;
img2 = cvCloneImage(img1);


3.4 設(shè)置或得到感興趣區(qū)域ROI
void cvSetImageROI(IpIImage* image, cvRect rect);
void cvResetImageROI(IpIImage* image);
vRect cvGetImageROI(const IpIImage* image);


4. 圖像的讀寫
4.1 從文件中獲取圖像
從文件中讀取圖像可以采用下面的語句:
IpIImage* img = 0;
img = cvLoadImage(filename);
if (!img)
printf("Could not load image file: %s\n", filename);


默認(rèn)為讀取三通道圖像。如果改變設(shè)置則采用如下的方式:
img = cvLoadImage(filename, flag);
當(dāng)flag > 0時,表示載入圖像為3通道彩色圖像;
當(dāng)flag = 0時,表示載入圖像為單通道灰色圖像;
當(dāng)flag < 0時,表示載入圖像由文件中的圖像通道數(shù)決定。


5. 圖像轉(zhuǎn)換
5.1 將灰度圖像轉(zhuǎn)換為彩色圖像
cvConvertImage(src, dst, flags = 0);
其中,src表示浮點(單字節(jié))灰度(彩色)圖像;
dst表示單字節(jié)灰度(彩色)圖像;
flags表示
+--- CV_CVTIMG_FLIP, 垂直翻轉(zhuǎn)
flags = |
+--- CV_CVTIMG_SWAP_RB, 交換R和B通道


5.2 將彩色圖像轉(zhuǎn)換為灰度圖像
cvCvtColor(cimg, gimg, CV_RGB2GRAY);


5.3 彩色空間的轉(zhuǎn)換
cvCvtColor(src, dst, code);
其中code為:CV_<X>2<Y>,而<X>,<Y> = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS。


6. 繪制命令
繪圖語句為:
cvRectangle, cvCircle, cvLine, cvPolyLine, cvFillPoly, cvInitFont, cvPutText。


先把需要縮放的部分用cvcopy出來,cvresize,然后再cvcopy回去


cvSetImageROI(img, roi1);IPLImage tempimg= cvCreateImage(//size must be the resized image size//);cvResizeImage(img,rempimg....);cvSetImageROI(img,newroi);cvCopy(tempimg,img);


其實他把這個問題復(fù)雜化了,對指定部分縮放,首先要說明自己對哪個部分


感興趣cvSetImageROI,通過這個函數(shù),圖像就僅僅剩下了ROI部分,然后


通過cvResize()把這個ROI區(qū)域按照自己的意愿放大縮小,我自己編程如下:


::cvSetImageROI(src,cvRect(src->width/4,src->height/4,src->width/2,src->height/2));
IplImage* temp=::cvCreateImage(cvSize(src->width,src->height),src->depth,src->nChannels);
::cvResize(src,temp);
::cvNamedWindow(wndName1,1);
::cvShowImage(wndName1,temp);
::cvWaitKey(0);


感興趣區(qū)域為中間的區(qū)域,大小為原來的1/2,重新劃分后感興趣區(qū)域為原來


大小,搞定。
========

OpenCv入門-圖像處理基本函數(shù)



1、圖像的內(nèi)存分配與釋放
(1) 分配內(nèi)存給一幅新圖像:
IplImage* cvCreateImage(CvSize size, int depth, int channels);
?
size: cvSize(width,height);
depth: 像素深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
? ?IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F
channels: 像素通道數(shù). Can be 1, 2, 3 or 4.
? ? ? ? ? ? ? ? ?各通道是交錯排列的. 一幅彩色圖像的數(shù)據(jù)排列格式如下:
? ? ? ? ? ? ? ? ?b0 g0 r0 b1 g1 r1 ...
?
示例:
// Allocate a 1-channel byte image
IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
?
// Allocate a 3-channel float image
IplImage* img2=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
?
?
(2) 釋放圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
cvReleaseImage(&img);
?
(3) 復(fù)制圖像:
IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
IplImage* img2;
img2=cvCloneImage(img1); ?// 注意通過cvCloneImage得到的圖像
? ? ? ? ? ? ? ? ? ? ? // 也要用 cvReleaseImage 釋放,否則容易產(chǎn)生內(nèi)存泄漏
?
(4) 設(shè)置/獲取感興趣區(qū)域ROI: ? ? ? ? (ROI:Region Of Interest) ? ? ?
void ?cvSetImageROI(IplImage* image, CvRect rect);
void ?cvResetImageROI(IplImage* image);
CvRect cvGetImageROI(const IplImage* image);
大多數(shù)OpenCV函數(shù)都支持 ROI.
?
(5) 設(shè)置/獲取感興趣通道COI: ? ? ? ? (COI:channel of interest)
void cvSetImageCOI(IplImage* image, int coi); // 0=all
int cvGetImageCOI(const IplImage* image);
大多數(shù)OpenCV函數(shù)不支持 COI.
?
2、圖像讀寫
(1) 從文件中讀入圖像:
IplImage* img=0;
? img=cvLoadImage(fileName);
? if(!img) printf("Could not load image file: %s\n",fileName);
?支持的圖像格式: BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM,
? ? ? ? ? ? ? ? ? ? ? ? ? SR, RAS, TIFF, TIF
OpenCV默認(rèn)將讀入的圖像強(qiáng)制轉(zhuǎn)換為一幅三通道彩色圖像. 不過可以按以下方法修改讀入方式:
img=cvLoadImage(fileName,flag);
?flag: >0 將讀入的圖像強(qiáng)制轉(zhuǎn)換為一幅三通道彩色圖像
? ? ? ?=0 將讀入的圖像強(qiáng)制轉(zhuǎn)換為一幅單通道灰度圖像
? ? ? ?<0 讀入的圖像通道數(shù)與所讀入的文件相同.
?
(2) 保存圖像:
if(!cvSaveImage(outFileName,img)) printf("Could not save: %s\n", outFileName);
保存的圖像格式由 outFileName 中的擴(kuò)展名確定.
?
3、訪問圖像像素
(1) 假設(shè)你要訪問第k通道、第i行、第j列的像素。
(2) 間接訪問: (通用,但效率低,可訪問任意格式的圖像)
對于單通道字節(jié)型圖像
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
CvScalar s;
s=cvGet2D(img,i,j); ? // get the (j,i) pixel value, 注意cvGet2D與cvSet2D中坐標(biāo)參數(shù)的順序與其它opencv函數(shù)坐標(biāo)參數(shù)順序恰好相反.本函數(shù)中i代表y軸,即height;j代表x軸,即weight.
printf("intensity=%f\n",s.val[0]);
s.val[0]=111;
cvSet2D(img,i,j,s); ? // set the (j,i) pixel value
?
對于多通道字節(jié)型/浮點型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
CvScalar s;
s=cvGet2D(img,i,j); // get the (j,i) pixel value
printf("B=%f, G=%f, R=%f\n",s.val[0],s.val[1],s.val[2]);
s.val[0]=111;
s.val[1]=111;
s.val[2]=111;
cvSet2D(img,i,j,s); // set the (j,i) pixel value
?
(3) 直接訪問: (效率高,但容易出錯)
? ? ? ?對于單通道字節(jié)型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
((uchar *)(img->imageData + i*img->widthStep))[j]=111; ? ? ? ? ? ? ? ? ? ? ? (img->imageData即數(shù)組首指針,i為行數(shù),img->widthStep每行所占字節(jié)數(shù))
? ? ? ?對于多通道字節(jié)型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
? ? ? ?對于多通道浮點型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
?
(4) 基于指針的直接訪問: (簡單高效)
? ? ? ?對于單通道字節(jié)型圖像:
IplImage* img ?= cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
int height ? ? = img->height;
int width ? ? ?= img->width;
int step ? ? ? = img->widthStep;
uchar* data ? ?= (uchar *)img->imageData;
data[i*step+j] = 111;
?
? ? ? ?對于多通道字節(jié)型圖像:
IplImage* img ?= cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
int height ? ? = img->height;
int width ? ? ?= img->width;
int step ? ? ? = img->widthStep;
int channels ? = img->nChannels;
uchar* data ? ?= (uchar *)img->imageData;
data[i*step+j*channels+k] = 111;
?
? ? ? ?對于多通道浮點型圖像(假設(shè)圖像數(shù)據(jù)采用4字節(jié)(32位)行對齊方式):
IplImage* img ?= cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
int height ? ? = img->height;
int width ? ? ?= img->width;
int step ? ? ? = img->widthStep;
int channels ? = img->nChannels;
float * data ? ?= (float *)img->imageData;
data[i*step+j*channels+k] = 111;
?
(5) 基于 c++ wrapper 的直接訪問: (更簡單高效) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (封裝?C++封裝沒怎么學(xué),要用再仔細(xì)學(xué))
? ? ? ?首先定義一個 c++ wrapper ‘Image’,然后基于Image定義不同類型的圖像:
template<class T> class Image
{
? private:
? IplImage* imgp;
? public:
? Image(IplImage* img=0) {imgp=img;}
? ~Image(){imgp=0;}
? void operator=(IplImage* img) {imgp=img;}
? inline T* operator[](const int rowIndx) {
? ? return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
};
?
typedef struct{
? unsigned char b,g,r;
} RgbPixel;
?
typedef struct{
? float b,g,r;
} RgbPixelFloat;
?
typedef Image<RgbPixel> ? ? ? RgbImage;
typedef Image<RgbPixelFloat> ?RgbImageFloat;
typedef Image<unsigned char> ?BwImage;
typedef Image<float> ? ? ? ? ?BwImageFloat;
?
? ? ? ?對于單通道字節(jié)型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
BwImage imgA(img);
imgA[i][j] = 111;
?
? ? ? ?對于多通道字節(jié)型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
RgbImage ?imgA(img);
imgA[i][j].b = 111;
imgA[i][j].g = 111;
imgA[i][j].r = 111;
?
? ? ? ?對于多通道浮點型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
RgbImageFloat imgA(img);
imgA[i][j].b = 111;
imgA[i][j].g = 111;
imgA[i][j].r = 111;
========

OpenCV中圖像處理函數(shù) ?



1。濾波 Filtering
filter2D() 用核函數(shù)對圖像做卷積


sepFilter2D() 用分解的核函數(shù)對圖像做卷積。首先,圖像的每一行與一維的核kernelX做卷積;然后,運算結(jié)果的每一列與一維的核kernelY做卷積


boxFilter() 就是滑動窗口平均濾波的二維版。
GaussianBlur() 高斯平均,也就是高斯模糊。
medianBlur() 中值濾波,個人最愛的濾波函數(shù)。
bilateralFilter() 雙線性濾波。
前面這四個函數(shù)是原來OpenCV里的cvSmooth()取不同參數(shù)的應(yīng)用。
Sobel() 使用擴(kuò)展 Sobel 算子計算一階、二階、三階或混合圖像差分。
Scharr() 計算一階導(dǎo),x方向或y方向,以前這個方法是放在cvSobel里的。
Laplacian() 拉普拉斯變換。
erode(), dilate() 腐蝕、膨脹。


示例:
filter2D(image, image, image.depth(), (Mat<float>(3,3)<<-1, -1, -1, -1, 9, -1, -1, -1, -1), Point(1,1), 128);
構(gòu)造了一個如下所示的核對圖像做卷積:
-1 -1 -1
-1 9 -1
-1 -1 -1
核的錨點在(1,1)位置,卷積之后每個像素加上128.
2。幾何變換 Geometrical Transformations
resize() 改變圖像尺寸,可以指定x方向和y方向上的縮放比例,可以指定插值方法。
getRectSubPix() 以亞像素精度從圖像中提取矩形。 dst(x,y)=src(x+center.x-(dst.cols-1)*0.5,y+center.y-(dst.rows-1)*0.5) 其中非整數(shù)象素點坐標(biāo)采用雙線性插值提取。
warpAffine() 仿射變換。
warpPerspective() 透射變換。
remap() 幾何變換。
convertMaps() 將圖像從一種類型,轉(zhuǎn)換成另一種類型。


示例:
Mat dst;
resize(src, dst, Size(), 1./sqrt(2), 1./sqrt(2)); // 把圖像縮小到原來的根號二分之一。
3。 圖像變換 Various Image Transformations
cvtColor()色彩空間轉(zhuǎn)換。這個函數(shù)可以用于把CCD的raw格式轉(zhuǎn)換為RGB,請參考,但是不能用于把灰度圖轉(zhuǎn)成偽彩圖,請參考。
threshold() ?二值化,常用操作,一般應(yīng)用時建議用大津算法,即使用THRESH_OTSU參數(shù)。
adaptivethreshold() ?自適應(yīng)閾值的二值化。
floodFill() ?填充連通域。
integral() ?計算積分圖像,一次或者二次。
distanceTransform() ?距離變換,對原圖像的每一個像素計算到最近非零像素的距離。
watershed() ?分水嶺圖像分割。
grabCut()
一種彩色圖像分割算法,效果可以參考這里。See the samples watershed.cpp and grabcut.cpp.
4。 直方圖 Histograms
calcHist() ?計算直方圖。
calcBackProject() ?計算反向投影。
equalizeHist() ?灰度圖像的直方圖均衡化,常用操作。
compareHist() ?比較兩個直方圖。
例子:計算圖像的色調(diào)-飽和度直方圖。
Mat hsv, H;
cvtColor(image, hsv, CVBGR2HSV);
int planes[]=f0, 1g, hsize[] = f32, 32g;
calcHist(&hsv, 1, planes, Mat(), H, 2, hsize, 0);
========

形態(tài)學(xué)圖像處理 膨脹與腐蝕

http://blog.csdn.net/poem_qianmo/article/details/23710721


寫作當(dāng)前博文時配套使用的OpenCV版本: 2.4.8


一、理論與概念講解——從現(xiàn)象到本質(zhì)


1.1 ?形態(tài)學(xué)概述


形態(tài)學(xué)(morphology)一詞通常表示生物學(xué)的一個分支,該分支主要研究動植物的形態(tài)和結(jié)構(gòu)。而我們圖像處理中指的形態(tài)學(xué),往往表示的是數(shù)學(xué)形態(tài)學(xué)。下面一起來了解數(shù)學(xué)形態(tài)學(xué)的概念。


數(shù)學(xué)形態(tài)學(xué)(Mathematical morphology) 是一門建立在格論和拓?fù)鋵W(xué)基礎(chǔ)之上的圖像分析學(xué)科,是數(shù)學(xué)形態(tài)學(xué)圖像處理的基本理論。其基本的運算包括:二值腐蝕和膨脹、二值開閉運算、骨架抽取、極限腐蝕、擊中擊不中變換、形態(tài)學(xué)梯度、Top-hat變換、顆粒分析、


流域變換、灰值腐蝕和膨脹、灰值開閉運算、灰值形態(tài)學(xué)梯度等。


簡單來講,形態(tài)學(xué)操作就是基于形狀的一系列圖像處理操作。OpenCV為進(jìn)行圖像的形態(tài)學(xué)變換提供了快捷、方便的函數(shù)。最基本的形態(tài)學(xué)操作有二種,他們是:膨脹與腐蝕(Dilation與Erosion)。


膨脹與腐蝕能實現(xiàn)多種多樣的功能,主要如下:


消除噪聲
分割(isolate)出獨立的圖像元素,在圖像中連接(join)相鄰的元素。
尋找圖像中的明顯的極大值區(qū)域或極小值區(qū)域
求出圖像的梯度
我們在這里給出下文會用到的,用于對比膨脹與腐蝕運算的“淺墨”字樣毛筆字原圖:


在進(jìn)行腐蝕和膨脹的講解之前,首先需要注意,腐蝕和膨脹是對白色部分(高亮部分)而言的,不是黑色部分。膨脹就是圖像中的高亮部分進(jìn)行膨脹,“領(lǐng)域擴(kuò)張”,效果圖擁有比原圖更大的高亮區(qū)域。腐蝕就是原圖中的高亮部分被腐蝕,“領(lǐng)域被蠶食”,效果圖擁有


比原圖更小的高亮區(qū)域。


1.2 膨脹


其實,膨脹就是求局部最大值的操作。


按數(shù)學(xué)方面來說,膨脹或者腐蝕操作就是將圖像(或圖像的一部分區(qū)域,我們稱之為A)與核(我們稱之為B)進(jìn)行卷積。


核可以是任何的形狀和大小,它擁有一個單獨定義出來的參考點,我們稱其為錨點(anchorpoint)。多數(shù)情況下,核是一個小的中間帶有參考點和實心正方形或者圓盤,其實,我們可以把核視為模板或者掩碼。


而膨脹就是求局部最大值的操作,核B與圖形卷積,即計算核B覆蓋的區(qū)域的像素點的最大值,并把這個最大值賦值給參考點指定的像素。這樣就會使圖像中的高亮區(qū)域逐漸增長。如下圖所示,這就是膨脹操作的初衷。


膨脹的數(shù)學(xué)表達(dá)式:


膨脹效果圖(毛筆字):
??
照片膨脹效果圖:


1.3 腐蝕


再來看一下腐蝕,大家應(yīng)該知道,膨脹和腐蝕是一對好基友,是相反的一對操作,所以腐蝕就是求局部最小值的操作。


我們一般都會把腐蝕和膨脹對應(yīng)起來理解和學(xué)習(xí)。下文就可以看到,兩者的函數(shù)原型也是基本上一樣的。


原理圖:


腐蝕的數(shù)學(xué)表達(dá)式:


腐蝕效果圖(毛筆字):


照片腐蝕效果圖:


二、深入——OpenCV源碼分析溯源


直接上源碼吧,在 …\opencv\sources\modules\imgproc\src\ morph.cpp路徑中 的第 1353行開始就為 erode(腐蝕)函數(shù)的源碼, 1361行為 dilate(膨脹)函數(shù)的源碼。


//-----------------------------------【erode()函數(shù)中文注釋版源代碼】----------------------------?
// ? ?說明:以下代碼為來自于計算機(jī)開源視覺庫OpenCV的官方源代碼?
// ? ?OpenCV源代碼版本:2.4.8?
// ? ?源碼路徑:…\opencv\sources\modules\imgproc\src\ morph.cpp?
// ? ?源文件中如下代碼的起始行數(shù):1353行?
// ? ?中文注釋by淺墨?
//-------------------------------------------------------------------------------------------------------- ?
void cv::erode( InputArray src, OutputArraydst, InputArray kernel,
? ? ? ? ? ? ? ? Point anchor, int iterations,
? ? ? ? ? ? ? ? int borderType, constScalar& borderValue )
{
//調(diào)用morphOp函數(shù),并設(shè)定標(biāo)識符為MORPH_ERODE
? ?morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType,borderValue );
}
//-----------------------------------【dilate()函數(shù)中文注釋版源代碼】----------------------------?
// ? ?說明:以下代碼為來自于計算機(jī)開源視覺庫OpenCV的官方源代碼?
// ? ?OpenCV源代碼版本:2.4.8?
// ? ?源碼路徑:…\opencv\sources\modules\imgproc\src\ morph.cpp?
// ? ?源文件中如下代碼的起始行數(shù):1361行?
// ? ?中文注釋by淺墨?
//--------------------------------------------------------------------------------------------------------?
void cv::dilate( InputArray src,OutputArray dst, InputArray kernel,
? ? ? ? ? ? ? ? ?Point anchor, int iterations,
? ? ? ? ? ? ? ? ?int borderType, constScalar& borderValue )
{
//調(diào)用morphOp函數(shù),并設(shè)定標(biāo)識符為MORPH_DILATE
? ?morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType,borderValue );
}
可以發(fā)現(xiàn)erode和dilate這兩個函數(shù)內(nèi)部就是調(diào)用了一下morphOp,只是他們調(diào)用morphOp時,第一個參數(shù)標(biāo)識符不同,一個為MORPH_ERODE(腐蝕),一個為MORPH_DILATE(膨脹)。


morphOp函數(shù)的源碼在…\opencv\sources\modules\imgproc\src\morph.cpp中的第1286行,有興趣的朋友們可以研究研究,這里就不費時費力花篇幅展開分析了。


三、淺出——API函數(shù)快速上手


3.1 ? 形態(tài)學(xué)膨脹——dilate函數(shù)


erode函數(shù),使用像素鄰域內(nèi)的局部極大運算符來膨脹一張圖片,從src輸入,由dst輸出。支持就地(in-place)操作。


函數(shù)原型:


C++: void dilate(
? InputArray src,
? OutputArray dst,
? InputArray kernel,
? Point anchor=Point(-1,-1),
? int iterations=1,
? int borderType=BORDER_CONSTANT,
? const Scalar& borderValue=morphologyDefaultBorderValue()?
);


參數(shù)詳解:


第一個參數(shù),InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像通道的數(shù)量可以是任意的,但圖像深度應(yīng)為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
第二個參數(shù),OutputArray類型的dst,即目標(biāo)圖像,需要和源圖片有一樣的尺寸和類型。
第三個參數(shù),InputArray類型的kernel,膨脹操作的核。若為NULL時,表示的是使用參考點位于中心3x3的核。
我們一般使用函數(shù) getStructuringElement配合這個參數(shù)的使用。getStructuringElement函數(shù)會返回指定形狀和尺寸的結(jié)構(gòu)元素(內(nèi)核矩陣)。


其中,getStructuringElement函數(shù)的第一個參數(shù)表示內(nèi)核的形狀,我們可以選擇如下三種形狀之一:


矩形: MORPH_RECT
交叉形: MORPH_CROSS
橢圓形: MORPH_ELLIPSE
而getStructuringElement函數(shù)的第二和第三個參數(shù)分別是內(nèi)核的尺寸以及錨點的位置。


我們一般在調(diào)用erode以及dilate函數(shù)之前,先定義一個Mat類型的變量來獲得getStructuringElement函數(shù)的返回值。對于錨點的位置,有默認(rèn)值Point(-1,-1),表示錨點位于中心。且需要注意,十字形的element形狀唯一依賴于錨點的位置。而在其他情況下,錨點只是


影響了形態(tài)學(xué)運算結(jié)果的偏移。


getStructuringElement函數(shù)相關(guān)的調(diào)用示例代碼如下:?


int g_nStructElementSize = 3; //結(jié)構(gòu)元素(內(nèi)核矩陣)的尺寸
?
? //獲取自定義核
Mat element = getStructuringElement(MORPH_RECT,
? Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),
? Point( g_nStructElementSize, g_nStructElementSize ));
調(diào)用這樣之后,我們便可以在接下來調(diào)用erode或dilate函數(shù)時,第三個參數(shù)填保存了getStructuringElement返回值的Mat類型變量。對應(yīng)于我們上面的示例,就是填element變量。


第四個參數(shù),Point類型的anchor,錨的位置,其有默認(rèn)值(-1,-1),表示錨位于中心。
第五個參數(shù),int類型的iterations,迭代使用erode()函數(shù)的次數(shù),默認(rèn)值為1。
第六個參數(shù),int類型的borderType,用于推斷圖像外部像素的某種邊界模式。注意它有默認(rèn)值BORDER_DEFAULT。
第七個參數(shù),const Scalar&類型的borderValue,當(dāng)邊界為常數(shù)時的邊界值,有默認(rèn)值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時,可以看官方文檔中的createMorphologyFilter()函數(shù)得到更詳細(xì)的解釋。
?
使用erode函數(shù),一般我們只需要填前面的三個參數(shù),后面的四個參數(shù)都有默認(rèn)值。而且往往結(jié)合getStructuringElement一起使用。


調(diào)用范例:


//載入原圖?
? ? Mat image = imread("1.jpg");
? ? //獲取自定義核
? ? Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
? ? Mat out;
? ? //進(jìn)行膨脹操作
? ? dilate(image, out, element);
用上面核心代碼架起來的完整程序代碼:


//-----------------------------------【頭文件包含部分】---------------------------------------
// ? ? 描述:包含程序所依賴的頭文件
//----------------------------------------------------------------------------------------------
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <iostream>
?
//-----------------------------------【命名空間聲明部分】---------------------------------------
// ? ? 描述:包含程序所使用的命名空間
//-----------------------------------------------------------------------------------------------?
using namespace std;
using namespace cv;
?
//-----------------------------------【main( )函數(shù)】--------------------------------------------
// ? ? 描述:控制臺應(yīng)用程序的入口函數(shù),我們的程序從這里開始
//-----------------------------------------------------------------------------------------------
int main( ?)
{
?
? //載入原圖?
? Mat image = imread("1.jpg");
?
? //創(chuàng)建窗口?
? namedWindow("【原圖】膨脹操作");
? namedWindow("【效果圖】膨脹操作");
?
? //顯示原圖
? imshow("【原圖】膨脹操作", image);
?
? //獲取自定義核
? Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
? Mat out;
? //進(jìn)行膨脹操作
? dilate(image,out, element);
?
? //顯示效果圖
? imshow("【效果圖】膨脹操作", out);
?
? waitKey(0);
?
? return 0;
}
?運行截圖:


3.2 ?形態(tài)學(xué)腐蝕——erode函數(shù)


erode函數(shù),使用像素鄰域內(nèi)的局部極小運算符來腐蝕一張圖片,從src輸入,由dst輸出。支持就地(in-place)操作。


看一下函數(shù)原型:


C++: void erode(
? InputArray src,
? OutputArray dst,
? InputArray kernel,
? Point anchor=Point(-1,-1),
? int iterations=1,
? int borderType=BORDER_CONSTANT,
? const Scalar& borderValue=morphologyDefaultBorderValue()
?);
參數(shù)詳解:


第一個參數(shù),InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像通道的數(shù)量可以是任意的,但圖像深度應(yīng)為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
第二個參數(shù),OutputArray類型的dst,即目標(biāo)圖像,需要和源圖片有一樣的尺寸和類型。
第三個參數(shù),InputArray類型的kernel,腐蝕操作的內(nèi)核。若為NULL時,表示的是使用參考點位于中心3x3的核。我們一般使用函數(shù) getStructuringElement配合這個參數(shù)的使用。getStructuringElement函數(shù)會返回指定形狀和尺寸的結(jié)構(gòu)元素(內(nèi)核矩陣)。(具體看上


文中淺出部分dilate函數(shù)的第三個參數(shù)講解部分)
第四個參數(shù),Point類型的anchor,錨的位置,其有默認(rèn)值(-1,-1),表示錨位于單位(element)的中心,我們一般不用管它。
第五個參數(shù),int類型的iterations,迭代使用erode()函數(shù)的次數(shù),默認(rèn)值為1。
第六個參數(shù),int類型的borderType,用于推斷圖像外部像素的某種邊界模式。注意它有默認(rèn)值BORDER_DEFAULT。
第七個參數(shù),const Scalar&類型的borderValue,當(dāng)邊界為常數(shù)時的邊界值,有默認(rèn)值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時,可以看官方文檔中的createMorphologyFilter()函數(shù)得到更詳細(xì)的解釋。
同樣的,使用erode函數(shù),一般我們只需要填前面的三個參數(shù),后面的四個參數(shù)都有默認(rèn)值。而且往往結(jié)合getStructuringElement一起使用。


調(diào)用范例:


//載入原圖?
? ? Mat image = imread("1.jpg");
? ? //獲取自定義核
? ? Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
? ? Mat out;
? ? //進(jìn)行腐蝕操作
? ? erode(image,out, element);
用上面核心代碼架起來的完整程序代碼:


//-----------------------------------【頭文件包含部分】---------------------------------------
// ? ? 描述:包含程序所依賴的頭文件
//----------------------------------------------------------------------------------------------
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <iostream>
?
//-----------------------------------【命名空間聲明部分】---------------------------------------
// ? ? 描述:包含程序所使用的命名空間
//-----------------------------------------------------------------------------------------------?
using namespace std;
using namespace cv;
?
//-----------------------------------【main( )函數(shù)】--------------------------------------------
// ? ? 描述:控制臺應(yīng)用程序的入口函數(shù),我們的程序從這里開始
//-----------------------------------------------------------------------------------------------
int main( ?)
{
? //載入原圖?
? Matimage = imread("1.jpg");
?
? ?//創(chuàng)建窗口?
? namedWindow("【原圖】腐蝕操作");
? namedWindow("【效果圖】腐蝕操作");
?
? //顯示原圖
? imshow("【原圖】腐蝕操作", image);
?
? ?
? //獲取自定義核
? Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
? Mat out;
?
? //進(jìn)行腐蝕操作
? erode(image,out, element);
?
? //顯示效果圖
? imshow("【效果圖】腐蝕操作", out);
?
? waitKey(0);
?
? return 0;
}
運行結(jié)果:


四、綜合示例——在實戰(zhàn)中熟稔


這個示例程序中的效果圖窗口有兩個滾動條,顧名思義,第一個滾動條“腐蝕/膨脹”用于在腐蝕/膨脹之間進(jìn)行切換;第二個滾動條”內(nèi)核尺寸”用于調(diào)節(jié)形態(tài)學(xué)操作時的內(nèi)核尺寸,以得到效果不同的圖像,有一定的可玩性。廢話不多說,上代碼吧:


//-----------------------------------【程序說明】----------------------------------------------
// ? ? 程序名稱::《【OpenCV入門教程之十】形態(tài)學(xué)圖像處理(一):膨脹與腐蝕 ?》 博文配套源碼
// ? ? 開發(fā)所用IDE版本:Visual Studio 2010
// ? 開發(fā)所用OpenCV版本: 2.4.8
// ? ? 2014年4月14日 Create by 淺墨
// ? ? 淺墨的微博:@淺墨_毛星云
//------------------------------------------------------------------------------------------------
?
//-----------------------------------【頭文件包含部分】---------------------------------------
// ? ? 描述:包含程序所依賴的頭文件
//----------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <iostream>
?
//-----------------------------------【命名空間聲明部分】---------------------------------------
// ? ? 描述:包含程序所使用的命名空間
//-----------------------------------------------------------------------------------------------
using namespace std;
using namespace cv;
?
?
//-----------------------------------【全局變量聲明部分】--------------------------------------
// ? ? 描述:全局變量聲明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage, g_dstImage;//原始圖和效果圖
int g_nTrackbarNumer = 0;//0表示腐蝕erode, 1表示膨脹dilate
int g_nStructElementSize = 3; //結(jié)構(gòu)元素(內(nèi)核矩陣)的尺寸
?
?
//-----------------------------------【全局函數(shù)聲明部分】--------------------------------------
// ? ? 描述:全局函數(shù)聲明
//-----------------------------------------------------------------------------------------------
void Process();//膨脹和腐蝕的處理函數(shù)
void on_TrackbarNumChange(int, void *);//回調(diào)函數(shù)
void on_ElementSizeChange(int, void *);//回調(diào)函數(shù)
?
?
//-----------------------------------【main( )函數(shù)】--------------------------------------------
// ? ? 描述:控制臺應(yīng)用程序的入口函數(shù),我們的程序從這里開始
//-----------------------------------------------------------------------------------------------
int main( )
{
? //改變console字體顏色
? system("color5E");?
?
? //載入原圖
? g_srcImage= imread("1.jpg");
? if(!g_srcImage.data ) { printf("Oh,no,讀取srcImage錯誤~!\n"); return false; }
? ? ??
? //顯示原始圖
? namedWindow("【原始圖】");
? imshow("【原始圖】", g_srcImage);
? ? ??
? //進(jìn)行初次腐蝕操作并顯示效果圖
? namedWindow("【效果圖】");
? //獲取自定義核
? Matelement = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),Point( g_nStructElementSize, g_nStructElementSize ));
? erode(g_srcImage,g_dstImage, element);
? imshow("【效果圖】", g_dstImage);
?
? //創(chuàng)建軌跡條
? createTrackbar("腐蝕/膨脹", "【效果圖】", &g_nTrackbarNumer, 1, on_TrackbarNumChange);
? createTrackbar("內(nèi)核尺寸", "【效果圖】",&g_nStructElementSize, 21, on_ElementSizeChange);
?
? //輸出一些幫助信息
? cout<<endl<<"\t嗯。運行成功,請調(diào)整滾動條觀察圖像效果~\n\n"
? ? <<"\t按下“q”鍵時,程序退出~!\n"
? ? <<"\n\n\t\t\t\tby淺墨";
?
? //輪詢獲取按鍵信息,若下q鍵,程序退出
? while(char(waitKey(1))!= 'q') {}
?
? return 0;
}
?
//-----------------------------【Process( )函數(shù)】------------------------------------
// ? ? 描述:進(jìn)行自定義的腐蝕和膨脹操作
//-----------------------------------------------------------------------------------------
void Process()
{
? //獲取自定義核
? Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),Point( g_nStructElementSize, g_nStructElementSize ));
?
? //進(jìn)行腐蝕或膨脹操作
? if(g_nTrackbarNumer== 0) { ??
? ? erode(g_srcImage,g_dstImage, element);
? }
? else{
? ? dilate(g_srcImage,g_dstImage, element);
? }
?
? //顯示效果圖
? imshow("【效果圖】", g_dstImage);
}
?
?
//-----------------------------【on_TrackbarNumChange( )函數(shù)】------------------------------------
// ? ? 描述:腐蝕和膨脹之間切換開關(guān)的回調(diào)函數(shù)
//-----------------------------------------------------------------------------------------------------
void on_TrackbarNumChange(int, void *)
{
? //腐蝕和膨脹之間效果已經(jīng)切換,回調(diào)函數(shù)體內(nèi)需調(diào)用一次Process函數(shù),使改變后的效果立即生效并顯示出來
? Process();
}
?
?
//-----------------------------【on_ElementSizeChange( )函數(shù)】-------------------------------------
// ? ? 描述:腐蝕和膨脹操作內(nèi)核改變時的回調(diào)函數(shù)
//-----------------------------------------------------------------------------------------------------
void on_ElementSizeChange(int, void *)
{
? //內(nèi)核尺寸已改變,回調(diào)函數(shù)體內(nèi)需調(diào)用一次Process函數(shù),使改變后的效果立即生效并顯示出來
? Process();
}
放出一些效果圖吧。原始 圖:


膨脹效果圖:


腐蝕效果圖:


腐蝕和膨脹得到的圖,都特有喜感,但千變?nèi)f變,還是原圖好看:


========

OpenCV圖像處理篇之腐蝕與膨脹



腐蝕與膨脹


腐蝕和膨脹是圖像的形態(tài)學(xué)處理中最基本的操作,之后遇見的開操作和閉操作都是腐蝕和膨脹操作的結(jié)合運算。腐蝕和膨脹的應(yīng)用非常廣泛,而且效果還很好:


腐蝕可以分割(isolate)獨立的圖像元素,膨脹用于連接(join)相鄰的元素,這也是腐蝕和膨脹后圖像最直觀的展現(xiàn)
去噪:通過低尺寸結(jié)構(gòu)元素的腐蝕操作很容易去掉分散的椒鹽噪聲點
圖像輪廓提取:腐蝕操作
圖像分割
等等...(在文后給出一則簡單實用膨脹操作提取車牌數(shù)字區(qū)域的例子)
結(jié)構(gòu)元素是形態(tài)學(xué)操作中最重要的概念,


erode_show dilate_show


如上圖,B為結(jié)構(gòu)元素。


腐蝕操作描述為:掃描圖像的每一個像素,用結(jié)構(gòu)元素與其覆蓋的二值圖像做“與”操作:如果都為1,結(jié)果圖像的該像素為1,否則為0。


膨脹操作描述為:掃描圖像的每一個像素,用結(jié)構(gòu)元素與其覆蓋的二值圖像做“與”操作:如果都為0,結(jié)果圖像的該像素為0,否則為1。


以上都是關(guān)于二值圖像的形態(tài)學(xué)操作,對于灰度圖像:


腐蝕操作


其中,g(x,y)為腐蝕后的灰度圖像,f(x,y)為原灰度圖像,B為結(jié)構(gòu)元素。腐蝕運算是由結(jié)構(gòu)元素確定的鄰域塊中選取圖像值與結(jié)構(gòu)元素值的差的最小值。


膨脹操作


其中,g(x,y)為腐蝕后的灰度圖像,f(x,y)為原灰度圖像,B為結(jié)構(gòu)元素。 膨脹運算是由結(jié)構(gòu)元素確定的鄰域塊中選取圖像值與結(jié)構(gòu)元素值的和的最大值。


在灰度圖的形態(tài)學(xué)操作中,一般選擇“平攤”的結(jié)構(gòu)元素,即結(jié)構(gòu)元素B的值為0,則上面對灰度圖的形態(tài)學(xué)操作可簡化如下:


好了,這就是基本的形態(tài)學(xué)操作——腐蝕和膨脹,下面是使用OpenCV對圖像進(jìn)行腐蝕和膨脹的程序,還是秉承我們一貫的原則:擱下理論,先直觀地感覺圖像處理算法的效果,實際項目需要時再深入挖掘!


程序分析


/*
?* FileName : eroding_and_dilating.cpp
?* Author ? : xiahouzuoxin @163.com
?* Version ?: v1.0
?* Date ? ? : Fri 19 Sep 2014 07:42:12 PM CST
?* Brief ? ?:?
?*?
?* Copyright (C) MICL,USTB
?*/
#include "cv.h"?
#include "highgui.h"
#include "opencv2/imgproc/imgproc.hpp"


using namespace std;
using namespace cv;


#define TYPE_MORPH_RECT ? ? ?(0)
#define TYPE_MORPH_CROSS ? ? (1)
#define TYPE_MORPH_ELLIPSE ? (2)


#define MAX_ELE_TYPE ? ? ? ? (2)
#define MAX_ELE_SIZE ? ? ? ? (20)


Mat src, erode_dst, dilate_dst;


const char *erode_wn ?= "eroding demo";
const char *dilate_wn = "dilating demo";


int erode_ele_type;
int dilate_ele_type;
int erode_ele_size;
int dilate_ele_size;


static void Erosion(int, void *);
static void Dilation(int, void *);


/*
?* @brief ??
?* @inputs ?
?* @outputs?
?* @retval ?
?*/
int main(int argc, char *argv[])
{
? ? if (argc < 2) {
? ? ? ? cout<<"Usage: ./eroding_and_dilating [file name]"<<endl;
? ? ? ? return -1;
? ? }


? ? src = imread(argv[1]);
? ? if (!src.data) {
? ? ? ? cout<<"Read image failure."<<endl;
? ? ? ? return -1;
? ? }


? ? // Windows
? ? namedWindow(erode_wn, WINDOW_AUTOSIZE);
? ? namedWindow(dilate_wn, WINDOW_AUTOSIZE);


? ? // Track Bar for Erosion
? ? createTrackbar("Element Type\n0:Rect\n1:Cross\n2:Ellipse", erode_wn,?
? ? ? ? ? ? &erode_ele_type, MAX_ELE_TYPE, Erosion); ?// callback @Erosion
? ? createTrackbar("Element Size: 2n+1", erode_wn,?
? ? ? ? ? ? &erode_ele_size, MAX_ELE_SIZE, Erosion);


? ? // Track Bar for Dilation
? ? createTrackbar("Element Type\n0:Rect\n1:Cross\n2:Ellipse", dilate_wn,?
? ? ? ? ? ? &dilate_ele_type, MAX_ELE_TYPE, Dilation); ?// callback @Erosion
? ? createTrackbar("Element Size: 2n+1", dilate_wn,?
? ? ? ? ? ? &dilate_ele_size, MAX_ELE_SIZE, Dilation);


? ? // Default start
? ? Erosion(0, 0);
? ? Dilation(0, 0);


? ? waitKey(0);


? ? return 0;
}


/*
?* @brief ? 腐蝕操作的回調(diào)函數(shù)
?* @inputs ?
?* @outputs?
?* @retval ?
?*/
static void Erosion(int, void *)
{
? ? int erode_type;


? ? switch (erode_ele_type) {
? ? case TYPE_MORPH_RECT:
? ? ? ?erode_type = MORPH_RECT;?
? ? ? ?break;
? ? case TYPE_MORPH_CROSS:
? ? ? ?erode_type = MORPH_CROSS;
? ? ? ?break;
? ? case TYPE_MORPH_ELLIPSE:
? ? ? ?erode_type = MORPH_ELLIPSE;
? ? ? ?break;
? ? default:
? ? ? ?erode_type = MORPH_RECT;
? ? ? ?break;
? ? }


? ? Mat ele = getStructuringElement(erode_type, Size(2*erode_ele_size+1, 2*erode_ele_size+1),?
? ? ? ? ? ? Point(erode_ele_size, erode_ele_size));


? ? erode(src, erode_dst, ele);


? ? imshow(erode_wn, erode_dst);
}


/*
?* @brief ? 膨脹操作的回調(diào)函數(shù)
?* @inputs ?
?* @outputs?
?* @retval ?
?*/
static void Dilation(int, void *)
{
? ? int dilate_type;


? ? switch (dilate_ele_type) {
? ? case TYPE_MORPH_RECT:
? ? ? ?dilate_type = MORPH_RECT;?
? ? ? ?break;
? ? case TYPE_MORPH_CROSS:
? ? ? ?dilate_type = MORPH_CROSS;
? ? ? ?break;
? ? case TYPE_MORPH_ELLIPSE:
? ? ? ?dilate_type = MORPH_ELLIPSE;
? ? ? ?break;
? ? default:
? ? ? ?dilate_type = MORPH_RECT;
? ? ? ?break;
? ? }


? ? Mat ele = getStructuringElement(dilate_type, Size(2*dilate_ele_size+1, 2*dilate_ele_size+1),?
? ? ? ? ? ? Point(dilate_ele_size, dilate_ele_size));


? ? dilate(src, dilate_dst, ele);


? ? imshow(dilate_wn, dilate_dst);
}
膨脹和腐蝕操作的函數(shù)分別是erode和dilate,傳遞給他們的參數(shù)也都依次是原圖像、形態(tài)學(xué)操作后的圖像、結(jié)構(gòu)元素ele。本程序中給出了3種結(jié)構(gòu)元素類型,分別是


#define TYPE_MORPH_RECT ? ? ?(0) ?// 矩形
#define TYPE_MORPH_CROSS ? ? (1) ?// 十字交叉型
#define TYPE_MORPH_ELLIPSE ? (2) ?// 橢圓型
再通過OpenCV提供的getStructuringElement函數(shù)創(chuàng)建Mat類型的結(jié)構(gòu)元素。


getStructuringElement的參數(shù)依次是結(jié)構(gòu)元素類型(OpenCV中提供了宏定義MORPH_RECT、MORPH_CROSS和MORPH_ELLIPSE表示)、結(jié)構(gòu)元素大小。


這里我們首次接觸了createTrackbar函數(shù)(聲明在highgui.hpp中),該函數(shù)的功能是給窗口添加滑動條。其原型是:


CV_EXPORTS int createTrackbar( const string& trackbarname, const string& winname,
? ? ? ? ? ? ? ? ? ? ? ? ?int* value, int count,
? ? ? ? ? ? ? ? ? ? ? ? ?TrackbarCallback onChange=0,
? ? ? ? ? ? ? ? ? ? ? ? ?void* userdata=0);
trackbarname為滑動條的名稱,將會顯示在滑動條的前面,參見結(jié)果中的圖片顯示; winname為窗口名; value為滑動條關(guān)聯(lián)的變量,如上面程序中第一個滑動條關(guān)聯(lián)到erode_ele_type,表示——當(dāng)滑動條滑動變化時,erode_ele_type的值發(fā)生響應(yīng)的變化; count表示


滑動條能滑動到的最大值; TrackbarCallback onChange其實是這個函數(shù)的關(guān)鍵,是滑動條變化時調(diào)用的回調(diào)函數(shù)。當(dāng)滑動條滑動時,value值發(fā)生變化,系統(tǒng)立刻調(diào)用onChange函數(shù),執(zhí)行相關(guān)的操作,回調(diào)函數(shù)的定義形式是固定的:


void onChange(int, void *)
程序中的回調(diào)函數(shù)Erosion和Dilation函數(shù)的定義都遵循該形式:


static void Erosion(int, void *);
static void Dilation(int, void *);
結(jié)果及實際應(yīng)用


對“黑白小豬”進(jìn)行膨脹操作的變化(隨著結(jié)構(gòu)元素大小的變化)如下圖:


dilating_demo


對“黑白小豬”進(jìn)行腐蝕操作的變化(隨著結(jié)構(gòu)元素大小的變化)如下圖:


eroding_demo


膨脹與腐蝕在圖像處理中具有廣泛的用途,比如提取車牌過程中,可以通過膨脹運算確定車牌的區(qū)域。如下圖為通過sobel算子提取邊緣后的車牌,


car_plate


為去掉邊界,確定車牌在圖中的位置,可以通過膨脹操作,結(jié)果如下:


car_plate_dilate


上圖中的紅線區(qū)域就是膨脹后能用于確定車牌的連通區(qū)域,再通過對連通區(qū)域的搜索及“車牌的矩形特性”即可確定含有車牌數(shù)字在圖片中的位置。


========

OpenCV&Qt學(xué)習(xí)之三-圖像的初步處理?Qt圖像的縮放顯示



實現(xiàn)圖像縮放的方法很多,在 OpenCV&Qt學(xué)習(xí)之一——打開圖片文件并顯示 的例程中,label控件是通過


ui->imagelabel->resize(ui->imagelabel->pixmap()->size());
來實現(xiàn)適應(yīng)圖像顯示的,但是由于窗口固定,在打開的圖像小于控件大小時就會縮在左上角顯示,在打開圖像過大時則顯示不全。因此這個例程中首先實現(xiàn)圖像適合窗口的縮放顯示。


由于是基于OpenCV和Qt的圖像處理,因此圖像的縮放處理在OpenCV和Qt都可以完成,我這里就把OpenCV用作圖像的原始處理,Qt用作顯示處理,因此縮放顯示由Qt完成。


Qt中QImage提供了用于縮放的基本函數(shù),而且功能非常強(qiáng)大,使用Qt自帶的幫助可以檢索到相關(guān)信息。


函數(shù)原型:


QImage QImage::scaled ( const QSize & size, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation ) const
這是直接獲取大小,還有另一種形式:


QImage QImage::scaled ( int width, int height, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation ) const
函數(shù)說明以及參數(shù)在文檔中已經(jīng)說的非常清楚了,文檔摘錄如下:
Returns a copy of the image scaled to a rectangle defined by the given size according to the given aspectRatioMode and transformMode.


image


If aspectRatioMode is Qt::IgnoreAspectRatio, the image is scaled to size.
If aspectRatioMode is Qt::KeepAspectRatio, the image is scaled to a rectangle as large as possible inside size, preserving the aspect ratio.
If aspectRatioMode is Qt::KeepAspectRatioByExpanding, the image is scaled to a rectangle as small as possible outside size, preserving the aspect ratio.


官方文檔中已經(jīng)說的比較清楚了,代碼實現(xiàn)也比較簡單,代碼如下:


{
? ? QImage imgScaled ;
? ? imgScaled = img.scaled(ui->imagelabel->size(),Qt::KeepAspectRatio);
// ?imgScaled = img.QImage::scaled(ui->imagelabel->width(),ui->imagelabel->height(),Qt::KeepAspectRatio);
? ? ui->imagelabel->setPixmap(QPixmap::fromImage(imgScaled));
}
顯示效果如下:


image


QImage的一點疑問與理解


在查找資料時參考了這篇 ?Qt中圖像的顯示與基本操作 博客,但是存在一些疑點,博客中相關(guān)代碼如下:


QImage* imgScaled = new QImage;
*imgScaled=img->scaled(width,height,Qt::KeepAspectRatio);
ui->label->setPixmap(QPixmap::fromImage(*imgScaled));


對于以上代碼通過和我之前的代碼做簡單對比,發(fā)現(xiàn)有幾點不一樣的地方:


圖像的定義方式,這里的定義方式為QImage* imgScale = new QImage
scaled函數(shù)的調(diào)用方式,一個是imgScaled = img.scaled后者為*imgScaled=img->scaled,我最開始也是將.寫為->一直沒找出錯誤,提示base operand of '->' has non-pointer type 'QImage'
繼續(xù)查找Qt的幫助手冊,發(fā)現(xiàn)QImage的構(gòu)造函數(shù)還真是多:


Public Functions


QImage ()


QImage ( const QSize & size, Format format )


QImage ( int width, int height, Format format )


QImage ( uchar * data, int width, int height, Format format )


QImage ( const uchar * data, int width, int height, Format format )


QImage ( uchar * data, int width, int height, int bytesPerLine, Format format )


QImage ( const uchar * data, int width, int height, int bytesPerLine, Format format )


QImage ( const char * const[] xpm )


QImage ( const QString & fileName, const char * format = 0 )


QImage ( const char * fileName, const char * format = 0 )


QImage ( const QImage & image )


~QImage ()


QImage提供了適用于不同場合的構(gòu)造方式,在手冊中對他們也有具體的應(yīng)用,但是我仍然沒找到QImage image;和QImage* image = new QImage這兩種究竟對應(yīng)的是哪兩種,有什么區(qū)別和不同。 在上一篇博文 ?OpenCV&Qt學(xué)習(xí)之二——QImage的進(jìn)一步認(rèn)識 ?中提到了對于


圖像數(shù)據(jù)的一點認(rèn)識,其中提到QImage是對現(xiàn)有數(shù)據(jù)的一種重新整合,是一種格式,但是數(shù)據(jù)還是指向原來的。從這里來看還需要根據(jù)構(gòu)造方式具體區(qū)別,并不完全正確。




凌亂查了查資料,網(wǎng)上的資料就那幾個,互相轉(zhuǎn)來轉(zhuǎn)去的,而且多數(shù)比較老,仍然沒有幫助我想通關(guān)于這里面數(shù)據(jù)結(jié)構(gòu)的一些疑問,Qt 和 OpenCV對C和指針的要求還是比較高的,長時間從單片機(jī)類的程序過來那點功底還真不夠,具體的C應(yīng)用都忘光了。這個問題只能暫


時擱置,在后面的學(xué)習(xí)中慢慢理解。




基于OpenCV的圖像初步處理


以下兩個例程根據(jù)書籍 OpenCV 2 Computer Vision Application Programming Cookbook中的相關(guān)例程整理,這是一本比較新也比較基礎(chǔ)的入門書籍。


salt-and-pepper noise


關(guān)于圖像數(shù)據(jù)的基礎(chǔ)知識參見這段介紹:


Fundamentally, an image is a matrix of numerical values. This is why OpenCV 2 manipulates them using the cv::Mat data structure. Each element of the matrix represents one pixel. For a gray-level image (a "black-and-white" image), pixels?


are unsigned 8-bit values where 0 corresponds to black and corresponds 255 to white. For a color image, three such values per pixel are required to represent the usual three primary color channels {Red, Green, Blue}. A matrix element is?


therefore made, in this case, of a triplet of values.


這兒以想圖像中添加saltand-pepper noise為例,來說明如何訪問圖像矩陣中的獨立元素。saltand-pepper noise就是圖片中一些像素點,隨機(jī)的被黑色或者白色的像素點所替代,因此添加saltand-pepper noise也比較簡單,只需要隨機(jī)的產(chǎn)生行和列,將這些行列值對


應(yīng)的像素值更改即可,當(dāng)然通過上面的介紹,需要更改RGB3個通道。程序如下:


void Widget::salt(cv::Mat &image, int n)
{


? ? int i,j;
? ? for (int k=0; k<n; k++)
? ? {


? ? ? ? i= qrand()%image.cols;
? ? ? ? j= qrand()%image.rows;


? ? ? ? if (image.channels() == 1) { // gray-level image


? ? ? ? ? ? image.at<uchar>(j,i)= 255;


? ? ? ? } else if (image.channels() == 3) { // color image


? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[0]= 255;
? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[1]= 255;
? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[2]= 255;
? ? ? ? }
? ? }
}


對Win 7系統(tǒng)中的自帶圖像考拉進(jìn)行處理后的效果如下圖所示(程序是Ubuntu 12.04下的):
image


減少色彩位數(shù)


在很多處理中需要對圖片中的所有像素進(jìn)行遍歷操作,采用什么方式進(jìn)行這個操作是需要思考的問題,關(guān)于這個問題的論述可以參考下面一段簡介:


Color images are composed of 3-channel pixels. Each of these channels corresponds to the intensity value of one of the three primary colors (red, green, blue). Since each of these values is an 8-bit unsigned char, the total number of?


colors is 256x256x256, which is more than 16 million colors. Consequently, to reduce the complexity of an analysis, it is sometimes useful to reduce the number of colors in an image. One simple way to achieve this goal is to simply?


subdivide the RGB space into cubes of equal sizes. For example, if you reduce the number of colors in each dimension by 8, then you would obtain a total of 32x32x32 colors. Each color in the original image is then assigned a new color?


value in the color-reduced image that corresponds to the value in the center of the cube to which it belongs.


這個例子就是通過操作每一個像素點來減少色彩的位數(shù),基本內(nèi)容在以上的英文引文中已經(jīng)有了介紹,代碼的實現(xiàn)也比較直接。在彩色圖像中,3個通道的數(shù)據(jù)是依次排列的,每一行的像素三個通道的值依次排列,cv::Mat中的通道排列順序為BGR,那么一個圖像需要的地


址塊空間為uchar 寬×高×3.但是需要注意的是,有些處理器針對行數(shù)為4或8的圖像處理更有效率,因此為了提高效率就會填充一些額外的像素,這些額外的像素不被顯示和保存,值是忽略的。


實現(xiàn)這個功能的代碼如下:


// using .ptr and []
void Widget::colorReduce0(cv::Mat &image, int div)
{


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line


? ? ? for (int j=0; j<nl; j++)
? ? ? {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++)
? ? ? ? ? {


? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? data[i]= data[i]/div*div+div/2;


? ? ? ? ? ? // end of pixel processing ----------------


? ? ? ? ? } // end of line
? ? ? }
}


data[i]= data[i]/div*div+div/2; 通過整除的方式,就像素位數(shù)進(jìn)行減少,這里沒明白的是為啥后面還要加上div/2。


效果如下:


image


程序源代碼:


#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent) :
? ? QWidget(parent),
? ? ui(new Ui::Widget)
{
? ? ui->setupUi(this);


}


Widget::~Widget()
{
? ? delete ui;
}


void Widget::on_openButton_clicked()
{
? ? QString fileName = QFileDialog::getOpenFileName(this,tr("Open Image"),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ".",tr("Image Files (*.png *.jpg *.bmp)"));
? ? qDebug()<<"filenames:"<<fileName;
? ? image = cv::imread(fileName.toAscii().data());
? ? ui->imgfilelabel->setText(fileName);
? ? //here use 2 ways to make a copy
// ? ?image.copyTo(originalimg); ? ? ? ? ?//make a copy
? ? originalimg = image.clone(); ? ? ? ?//clone the img
? ? qimg = Widget::Mat2QImage(image);
? ? display(qimg); ? ? ? ? ? ? ? ? ? ? ?//display by the label
? ? if(image.data)
? ? {
? ? ? ? ui->saltButton->setEnabled(true);
? ? ? ? ui->originalButton->setEnabled(true);
? ? ? ? ui->reduceButton->setEnabled(true);
? ? }
}


QImage Widget::Mat2QImage(const cv::Mat &mat)
{
? ? QImage img;
? ? if(mat.channels()==3)
? ? {
? ? ? ? //cvt Mat BGR 2 QImage RGB
? ? ? ? cvtColor(mat,rgb,CV_BGR2RGB);
? ? ? ? img =QImage((const unsigned char*)(rgb.data),
? ? ? ? ? ? ? ? ? ? rgb.cols,rgb.rows,
? ? ? ? ? ? ? ? ? ? rgb.cols*rgb.channels(),
? ? ? ? ? ? ? ? ? ? QImage::Format_RGB888);
? ? }
? ? else
? ? {
? ? ? ? img =QImage((const unsigned char*)(mat.data),
? ? ? ? ? ? ? ? ? ? mat.cols,mat.rows,
? ? ? ? ? ? ? ? ? ? mat.cols*mat.channels(),
? ? ? ? ? ? ? ? ? ? QImage::Format_RGB888);
? ? }
? ? return img;
}


void Widget::display(QImage img)
{
? ? QImage imgScaled;
? ? imgScaled = img.scaled(ui->imagelabel->size(),Qt::KeepAspectRatio);
// ?imgScaled = img.QImage::scaled(ui->imagelabel->width(),ui->imagelabel->height(),Qt::KeepAspectRatio);
? ? ui->imagelabel->setPixmap(QPixmap::fromImage(imgScaled));
}


void Widget::on_originalButton_clicked()
{
? ? qimg = Widget::Mat2QImage(originalimg);
? ? display(qimg);
}


void Widget::on_saltButton_clicked()
{
? ? salt(image,3000);
? ? qimg = Widget::Mat2QImage(image);
? ? display(qimg);
}
void Widget::on_reduceButton_clicked()
{
? ? colorReduce0(image,64);
? ? qimg = Widget::Mat2QImage(image);
? ? display(qimg);
}
void Widget::salt(cv::Mat &image, int n)
{


? ? int i,j;
? ? for (int k=0; k<n; k++)
? ? {


? ? ? ? i= qrand()%image.cols;
? ? ? ? j= qrand()%image.rows;


? ? ? ? if (image.channels() == 1)
? ? ? ? { // gray-level image


? ? ? ? ? ? image.at<uchar>(j,i)= 255;


? ? ? ? }
? ? ? ? else if (image.channels() == 3)
? ? ? ? { // color image


? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[0]= 255;
? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[1]= 255;
? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[2]= 255;
? ? ? ? }
? ? }
}


// using .ptr and []
void Widget::colorReduce0(cv::Mat &image, int div)
{


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line


? ? ? for (int j=0; j<nl; j++)
? ? ? {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++)
? ? ? ? ? {


? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? data[i]= data[i]/div*div+div/2;


? ? ? ? ? ? // end of pixel processing ----------------


? ? ? ? ? } // end of line
? ? ? }
}


#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include <QImage>
#include <QFileDialog>
#include <QTimer>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


namespace Ui {
class Widget;
}


class Widget : public QWidget
{
? ? Q_OBJECT
? ??
public:
? ? explicit Widget(QWidget *parent = 0);
? ? ~Widget();


private slots:
? ? void on_openButton_clicked();
? ? QImage Mat2QImage(const cv::Mat &mat);
? ? void display(QImage image);
? ? void salt(cv::Mat &image, int n);




? ? void on_saltButton_clicked();
? ? void on_reduceButton_clicked();
? ? void colorReduce0(cv::Mat &image, int div);


? ? void on_originalButton_clicked();


private:
? ? Ui::Widget *ui;
? ? cv::Mat image;
? ? cv::Mat originalimg; //store the original img
? ? QImage qimg;
? ? QImage imgScaled;
? ? cv::Mat rgb;
};


#endif // WIDGET_H


書中還給了其他十余種操作的方法:


#include <iostream>


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>


// using .ptr and []
void colorReduce0(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? data[i]= data[i]/div*div + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}


// using .ptr and * ++?
void colorReduce1(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ?*data++= *data/div*div + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}


// using .ptr and * ++ and modulo
void colorReduce2(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ?
? ? ? ? ? ? ? ? ? int v= *data;
? ? ? ? ? ? ? ? ? *data++= v - v%div + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}


// using .ptr and * ++ and bitwise
void colorReduce3(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line
? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? *data++= *data&mask + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}




// direct pointer arithmetic
void colorReduce4(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line
? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? int step= image.step; // effective width
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
? ? ? ? ? ? ??
? ? ? // get the pointer to the image buffer
? ? ? uchar *data= image.data;


? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? *(data+i)= *data&mask + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??


? ? ? ? ? ? data+= step; ?// next line
? ? ? }
}


// using .ptr and * ++ and bitwise with image.cols * image.channels()
void colorReduce5(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<image.cols * image.channels(); i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? *data++= *data&mask + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}


// using .ptr and * ++ and bitwise (continuous)
void colorReduce6(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols * image.channels(); // total number of elements per line


? ? ? if (image.isContinuous()) ?{
? ? ? ? ? // then no padded pixels
? ? ? ? ? nc= nc*nl;?
? ? ? ? ? nl= 1; ?// it is now a 1D array
? ? ? ?}


? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? *data++= *data&mask + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}


// using .ptr and * ++ and bitwise (continuous+channels)
void colorReduce7(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols ; // number of columns


? ? ? if (image.isContinuous()) ?{
? ? ? ? ? // then no padded pixels
? ? ? ? ? nc= nc*nl;?
? ? ? ? ? nl= 1; ?// it is now a 1D array
? ? ? ?}


? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? *data++= *data&mask + div/2;
? ? ? ? ? ? *data++= *data&mask + div/2;
? ? ? ? ? ? *data++= *data&mask + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}




// using Mat_ iterator?
void colorReduce8(cv::Mat &image, int div=64) {


? ? ? // get iterators
? ? ? cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
? ? ? cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();


? ? ? for ( ; it!= itend; ++it) {
? ? ? ??
? ? ? ? // process each pixel ---------------------


? ? ? ? (*it)[0]= (*it)[0]/div*div + div/2;
? ? ? ? (*it)[1]= (*it)[1]/div*div + div/2;
? ? ? ? (*it)[2]= (*it)[2]/div*div + div/2;


? ? ? ? // end of pixel processing ----------------
? ? ? }
}


// using Mat_ iterator and bitwise
void colorReduce9(cv::Mat &image, int div=64) {


? ? ? // div must be a power of 2
? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0


? ? ? // get iterators
? ? ? cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
? ? ? cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();


? ? ? // scan all pixels
? ? ? for ( ; it!= itend; ++it) {
? ? ? ??
? ? ? ? // process each pixel ---------------------


? ? ? ? (*it)[0]= (*it)[0]&mask + div/2;
? ? ? ? (*it)[1]= (*it)[1]&mask + div/2;
? ? ? ? (*it)[2]= (*it)[2]&mask + div/2;


? ? ? ? // end of pixel processing ----------------
? ? ? }
}


// using MatIterator_?
void colorReduce10(cv::Mat &image, int div=64) {


? ? ? // get iterators
? ? ? cv::Mat_<cv::Vec3b> cimage= image;
? ? ? cv::Mat_<cv::Vec3b>::iterator it=cimage.begin();
? ? ? cv::Mat_<cv::Vec3b>::iterator itend=cimage.end();


? ? ? for ( ; it!= itend; it++) {?
? ? ? ??
? ? ? ? // process each pixel ---------------------


? ? ? ? (*it)[0]= (*it)[0]/div*div + div/2;
? ? ? ? (*it)[1]= (*it)[1]/div*div + div/2;
? ? ? ? (*it)[2]= (*it)[2]/div*div + div/2;


? ? ? ? // end of pixel processing ----------------
? ? ? }
}




void colorReduce11(cv::Mat &image, int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols; // number of columns
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {
? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[0]= ? ? image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;
? ? ? ? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[1]= ? ? image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;
? ? ? ? ? ? ? ? ? image.at<cv::Vec3b>(j,i)[2]= ? ? image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}


// with input/ouput images
void colorReduce12(const cv::Mat &image, // input image?
? ? ? ? ? ? ? ? ?cv::Mat &result, ? ? ?// output image
? ? ? ? ? ? ? ? ?int div=64) {


? ? ? int nl= image.rows; // number of lines
? ? ? int nc= image.cols ; // number of columns


? ? ? // allocate output image if necessary
? ? ? result.create(image.rows,image.cols,image.type());


? ? ? // created images have no padded pixels
? ? ? nc= nc*nl;?
? ? ? nl= 1; ?// it is now a 1D array


? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
? ? ? ? ? ? ??
? ? ? for (int j=0; j<nl; j++) {


? ? ? ? ? uchar* data= result.ptr<uchar>(j);
? ? ? ? ? const uchar* idata= image.ptr<uchar>(j);


? ? ? ? ? for (int i=0; i<nc; i++) {
?
? ? ? ? ? ? // process each pixel ---------------------
? ? ? ? ? ? ? ? ?
? ? ? ? ? ? *data++= (*idata++)&mask + div/2;
? ? ? ? ? ? *data++= (*idata++)&mask + div/2;
? ? ? ? ? ? *data++= (*idata++)&mask + div/2;
?
? ? ? ? ? ? // end of pixel processing ----------------
?
? ? ? ? ? } // end of line ? ? ? ? ? ? ? ? ??
? ? ? }
}


// using overloaded operators
void colorReduce13(cv::Mat &image, int div=64) {
? ??
? ? ? int n= static_cast<int>(log(static_cast<double>(div))/log(2.0));
? ? ? // mask used to round the pixel value
? ? ? uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0


? ? ? // perform color reduction
? ? ? image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2);
}


========

OpenCV圖像處理 空間域圖像增強(qiáng)

(圖像銳化 1 基于拉普拉斯算子) ?




OpenCV
OpenCV 圖像銳化
拉普拉斯算子 ( Laplacian operator )
Quote :


It is indeed a well-known result in image processing that if you subtract its Laplacian from an image, the image edges are amplified giving a sharper image. [From OpenCV 2 Computer Vision Application Programming Cookbook]


對于求一個銳化后的像素點(sharpened_pixel),這個基于拉普拉斯算子的簡單算法主要是遍歷圖像中的像素點,根據(jù)領(lǐng)域像素確定其銳化后的值
計算公式:sharpened_pixel = 5 * current – left – right – up – down ; [見Code1]
OpenCV圖像處理 空間域圖像增強(qiáng)(圖像銳化 1 基于拉普拉斯算子) - ___________杰 - __________Ggicci
?
當(dāng)一個運算是通過領(lǐng)域像素進(jìn)行的時候,我們通常用一個矩陣來表示這種運算關(guān)系,也就是我們經(jīng)常所說的 核 (Kernel) 。那么上面的 銳化濾波器 (Sharpening Filter) 就可以用這個矩陣表示為它的核:
? -1 ?
-1 5 -1
? -1 ?
因為 濾波 在圖像處理中是一個非常普通且常用的操作,所以O(shè)penCV里面已經(jīng)定義了一個特殊的函數(shù)用來執(zhí)行這個操作。要使用它的話只需要定義一個 核 ,然后作為參數(shù)傳遞就行了。[見Code2]
Code 1 :


/*
? ? Author ?: Ggicci
? ? Date ? ?: ?2012.07.19
? ? File ? ?: ?sharp.h
*/
#pragma once
#include <opencv\cv.h>
using namespace cv;
namespace ggicci
{
? ? void sharpen(const Mat& img, Mat& result);
}
/*
? ? Author ?: Ggicci
? ? Date ? ?: ?2012.07.19
? ? File ? ?: ?sharp.cpp
*/
#include "sharp.h"
void ggicci::sharpen(const Mat& img, Mat& result)
{ ? ?
? ? result.create(img.size(), img.type());
? ? //處理邊界內(nèi)部的像素點, 圖像最外圍的像素點應(yīng)該額外處理
? ? for (int row = 1; row < img.rows-1; row++)
? ? {
? ? ? ? //前一行像素點
? ? ? ? const uchar* previous = img.ptr<const uchar>(row-1);
? ? ? ? //待處理的當(dāng)前行
? ? ? ? const uchar* current = img.ptr<const uchar>(row);
? ? ? ? //下一行
? ? ? ? const uchar* next = img.ptr<const uchar>(row+1);
? ? ? ? uchar *output = result.ptr<uchar>(row);
? ? ? ? int ch = img.channels();
? ? ? ? int starts = ch;
? ? ? ? int ends = (img.cols - 1) * ch;
? ? ? ? for (int col = starts; col < ends; col++)
? ? ? ? {
? ? ? ? ? ? //輸出圖像的遍歷指針與當(dāng)前行的指針同步遞增, 以每行的每一個像素點的每一個通道值為一個遞增量, 因為要考慮到圖像的通道數(shù)
? ? ? ? ? ? *output++ = saturate_cast<uchar>(5 * current[col] - current[col-ch] - current[col+ch] - previous[col] - next[col]);
? ? ? ? }
? ? } //end loop
? ? //處理邊界, 外圍像素點設(shè)為 0
? ? result.row(0).setTo(Scalar::all(0));
? ? result.row(result.rows-1).setTo(Scalar::all(0));
? ? result.col(0).setTo(Scalar::all(0));
? ? result.col(result.cols-1).setTo(Scalar::all(0));
}
/*
? ? Author ?: ?Ggicci
? ? Date ? ?: ?2012.07.19
? ? File ? ?: ?main.cpp
*/
#include <opencv\highgui.h>
#pragma comment(lib, "opencv_core231d.lib")
#pragma comment(lib, "opencv_highgui231d.lib")
#pragma comment(lib, "opencv_imgproc231d.lib")
using namespace cv;
?
#include "sharp.h"
?
int main()
{ ? ?
? ? Mat lena = imread("lena.jpg");
? ? Mat sharpenedLena;
? ? ggicci::sharpen(lena, sharpenedLena);
?
? ? imshow("lena", lena);
? ? imshow("sharpened lena", sharpenedLena);
? ? cvWaitKey();
? ? return 0;
}
Output 1 :




OpenCV圖像處理 空間域圖像增強(qiáng)(圖像銳化 1 基于拉普拉斯算子) - ___________杰 - __________Ggicci
?
Code 2 :


? ?1: int main()
? ?2: { ? ?
? ?3: ? ? Mat lena = imread("lena.jpg");
? ?4: ? ? Mat sharpenedLena;
? ?5: ? ? Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
? ?6: ? ? cv::filter2D(lena, sharpenedLena, lena.depth(), kernel);
? ?7: ?
? ?8: ? ? imshow("lena", lena);
? ?9: ? ? imshow("sharpened lena", sharpenedLena);
? 10: ? ? cvWaitKey();
? 11: ? ? return 0;
? 12: }
Output 2 :
OpenCV圖像處理 空間域圖像增強(qiáng)(圖像銳化 1 基于拉普拉斯算子) - ___________杰 - __________Ggicci
?
End :


Author : Ggicci




========

OpenCV圖像處理 圖像的點運算??灰度直方圖?



OpenCV灰度直方圖
Theory :


從圖形上看,灰度直方圖是一個二維圖:


gray_hist


圖像的灰度直方圖是一個離散函數(shù),它表示圖像每一灰度級與該灰度級出現(xiàn)頻率的對應(yīng)關(guān)系。假設(shè)一幅圖像的像素總數(shù)為 N,灰度級總數(shù)為 L,其中灰度級為 g 的像素總數(shù)為 Ng,則這幅數(shù)字圖像的灰度直方圖橫坐標(biāo)即為灰度 g ( 0 ≤ g ≤ L-1 ),縱坐標(biāo)則為灰度值


出現(xiàn)的次數(shù) Ng。實際上,用 N 去除各個灰度值出現(xiàn)的次數(shù) Ng 即可得到各個灰度級出現(xiàn)的概率 Pg = Ng / N = Ng / ∑Ng ,從而得到歸一化的灰度直方圖,其縱坐標(biāo)為概率 Pg 。


Quote : ( From [OpenCV 2 Computer Vision Application Programming Cookbook (Robert Langaniere, 2011) ], 引用作直方圖的解釋 )


A histogram is a simple table that gives the number of pixels that have a given value in an image (or sometime a set of images). The histogram of a gray-level image will therefore have 256 entries (or bins).
Histograms can also be normalized such that sum of the bins equals 1. In that case, each bin gives the percentage of pixels having this specific value in the image.
Implementation :


利用 OpenCV 提供的 calcHist 函數(shù) :


void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false );


這個函數(shù)用于計算直方圖是很強(qiáng)大的,在這里就實現(xiàn)一個最簡單的灰度圖像的直方圖計算。


Code :


? ?int main()
? ?{ ? ?
? ? ? ?Mat img = imread("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
? ?
? ? ? ?Mat* arrays = &img;
? ? ? ?int narrays = 1;
? ? ? ?int channels[] = { 0 };
? ? ? ?InputArray mask = noArray();
? ? ? ?Mat hist;
? ? ? ?int dims = 1;
? ? ? ?int histSize[] = { 256 }; ? ?
? ? ? ?float hranges[] = { 0.0, 255.0 };
? ? ? ?const float *ranges[] = { hranges };
? ? ? ?//調(diào)用 calcHist 計算直方圖, 結(jié)果存放在 hist 中
? ? ? ?calcHist(arrays, narrays, channels, mask, hist, dims, histSize, ranges);
? ? ? ?
? ? ? ?//調(diào)用一個我自己寫的簡單的函數(shù)用于獲取一張顯示直方圖數(shù)據(jù)的圖片,
? ? ? ?//輸入?yún)?shù)為直方圖數(shù)據(jù) hist 和期望得到的圖片的尺寸
? ? ? ?Mat histImg = ggicci::getHistogram1DImage(hist, Size(600, 420));
? ? ? ?imshow("lena gray image histogram", histImg);
? ? ? ?waitKey();
? ?}
? ?
? ?Mat ggicci::getHistogram1DImage(const Mat& hist, Size imgSize)
? ?{
? ? ? ?Mat histImg(imgSize, CV_8UC3);
? ? ? ?int Padding = 10;
? ? ? ?int W = imgSize.width - 2 * Padding;
? ? ? ?int H = imgSize.height - 2 * Padding;
? ? ? ?double _max;
? ? ? ?minMaxLoc(hist, NULL, &_max);
? ? ? ?double Per = (double)H / _max;
? ? ? ?const Point Orig(Padding, imgSize.height-Padding);
? ? ? ?int bin = W / (hist.rows + 2);
? ?
? ? ? ?//畫方柱
? ? ? ?for (int i = 1; i <= hist.rows; i++)
? ? ? ?{
? ? ? ? ? ?Point pBottom(Orig.x + i * bin, Orig.y);
? ? ? ? ? ?Point pTop(pBottom.x, pBottom.y - Per * hist.at<float>(i-1));
? ? ? ? ? ?line(histImg, pBottom, pTop, Scalar(255, 0, 0), bin);
? ? ? ?}
? ?
? ? ? ?//畫 3 條紅線標(biāo)明區(qū)域
? ? ? ?line(histImg, Point(Orig.x + bin, Orig.y - H), Point(Orig.x + hist.rows * ?bin, Orig.y - H), Scalar(0, 0, 255), 1);
? ? ? ?line(histImg, Point(Orig.x + bin, Orig.y), Point(Orig.x + bin, Orig.y - H), Scalar(0, 0, 255), 1);
? ? ? ?line(histImg, Point(Orig.x + hist.rows * bin, Orig.y), Point(Orig.x + hist.rows * ?bin, Orig.y - H), Scalar(0, 0, 255), 1);
? ? ? ?drawArrow(histImg, Orig, Orig+Point(W, 0), 10, 30, Scalar::all(0), 2);
? ? ? ?drawArrow(histImg, Orig, Orig-Point(0, H), 10, 30, Scalar::all(0), 2);
? ? ? ?
? ? ? ?return histImg;
? ?}
Result :


lenaimage


airplaneimage


End :


Author : Ggicci




========

OpenCV:圖像的加載顯示及簡單變換?



摘要(Abstract) 通過筆記一的學(xué)習(xí),我們已經(jīng)能夠下載、安裝OpenCV并新建VS2010項目進(jìn)行相關(guān)的配置,筆記一也已完成第一個程序HelloCV的演示。本文首先通過詳細(xì)介紹OpenCV中如何從硬盤加載/讀取一幅圖像,并在窗口中進(jìn)行顯示來對筆記一中的演示程序做詳解


。其次,本文實現(xiàn)了簡單的圖像變換,將一幅RGB顏色的圖片lena.jpg轉(zhuǎn)化成灰度圖像,以達(dá)到修改的目的,另外,在此變換中,我們還對如何將圖片保存到硬盤上進(jìn)行講解。實驗結(jié)果表明,通過筆記二的學(xué)習(xí),不但能夠增強(qiáng)對OpenCV的學(xué)習(xí)興趣,還能有初體驗OpenCV的


成就感,吃嘛嘛香,為后續(xù)的學(xué)習(xí)打下堅實的基礎(chǔ)。


1、加載并顯示圖像(Load and Display an Image)
?
1.1 學(xué)習(xí)目標(biāo)
?
在本節(jié)中,我們預(yù)期達(dá)到以下學(xué)習(xí)目標(biāo):1) 加載一幅圖像(采用imread方法);2)創(chuàng)建一個指定的OpenCV窗口(采用namedWindow方法);3)在OpenCV窗口中顯示圖像(采用imshow方法)。
?
1.2 源代碼
?
#include “StdAfx.h”
?
#include <string>
?
#include <iostream>
?
#include <opencv2\core\core.hpp>
?
#include <opencv2\highgui\highgui.hpp>
?
using namespace cv;
?
using namespace std;
?
int main()
?
{
?
? ? ? ? ?string imageName = “l(fā)ena.jpg”;
?
? ? ? ? ?//讀入圖像
?
? ? ? ? ?Mat img = imread(imageName, CV_LOAD_IMAGE_COLOR);
?
?
?
? ? ? ? ?//如果讀入圖像失敗
?
? ? ? ? ?if (img.empty())
?
? ? ? ? ?{
?
? ? ? ? ? ? ? ? ? ?cout<<”Could not open or find the image!”<<endl;
?
? ? ? ? ? ? ? ? ? ?return -1;
?
? ? ? ? ?}
?
?
?
? ? ? ? ?//創(chuàng)建窗口
?
? ? ? ? ?namedWindow(“l(fā)ena”, CV_WINDOW_AUTOSIZE);
?
?
?
? ? ? ? ?//顯示圖像
?
? ? ? ? ?imshow(“l(fā)ena”, img);
?
?
?
? ? ? ? ?//等待按鍵,按鍵盤任意鍵返回
?
? ? ? ? ?waitKey();
?
?
?
? ? ? ? ?return 0;
?
}
?
1.3 源碼詳解
?
1.3.1 頭文件
?
OpenCV有許多不同的模塊,每個模塊關(guān)心圖像處理中不同的領(lǐng)域及方法(參見:OpenCV學(xué)習(xí)筆記(基于OpenCV 2.4)一:哈嘍CV),在使用之前我們首先需要對相應(yīng)的頭文件進(jìn)行包含,一般情況下我們都會用到的兩個模塊:
?
1)core section. 這里定義了OpenCV的一些基本的塊(Blocks);
?
2)highgui module. 該模塊包含了一些圖像的輸入輸出操作(UI)。
?
另外,為了能夠在控制臺做輸入輸出,我們會包含iostream,而string是用于字符串的處理。接下來,為了防止OpenCV的數(shù)據(jù)結(jié)構(gòu)或命名與其它庫函數(shù)比如STL有沖突,我們引入命名空間cv,在有沖突的情況下可以用前綴cv::來指定具體使用哪個庫(關(guān)于命名空間,我們


會在下一講做詳細(xì)介紹)。
?
1.3.2 主函數(shù)
?
--------------------------------------------------------------------------------




Mat img = imread(imageName, CV_LOAD_IMAGE_COLOR);
?


--------------------------------------------------------------------------------


imread的函數(shù)原型是:Mat imread( const string& filename, int flags=1 );
?
Mat是OpenCV里的一個數(shù)據(jù)結(jié)構(gòu),在這里我們定義一個Mat類型的變量img,用于保存讀入的圖像,在本文開始有寫到,我們用imread函數(shù)來讀取圖像,第一個字段標(biāo)識圖像的文件名(包括擴(kuò)展名),第二個字段用于指定讀入圖像的顏色和深度,它的取值可以有以下幾種:
?
1) CV_LOAD_IMAGE_UNCHANGED (<0),以原始圖像讀取(包括alpha通道),
?
2) CV_LOAD_IMAGE_GRAYSCALE ( 0),以灰度圖像讀取
?
3) CV_LOAD_IMAGE_COLOR (>0),以RGB格式讀取
?
這三點是在OpenCV的官方教程(opencv_tutorials.pdf)里摘錄并翻譯過來的,但是網(wǎng)上還有關(guān)于CV_LOAD_IMAGE_ANYDEPTH和CV_LOAD_IMAGE_ANYCOLOR的傳說,而且查看OpenCV的源碼可以發(fā)現(xiàn),這些取值放在一個枚舉(enum)類型中(opencv\build\include


\opencv2\highgui\highgui_c.h),定義如下:
?
enum
?
{
?
/* 8bit, color or not */
?
? ? CV_LOAD_IMAGE_UNCHANGED ?=-1,
?
/* 8bit, gray */
?
? ? CV_LOAD_IMAGE_GRAYSCALE ?=0,
?
/* ?, color */
?
? ? CV_LOAD_IMAGE_COLOR ? ? ?=1,
?
/* any depth, ? */
?
? ? CV_LOAD_IMAGE_ANYDEPTH ? =2,
?
/* ?, any color */
?
? ? CV_LOAD_IMAGE_ANYCOLOR ? =4
?
};
?
關(guān)于該枚舉類型的詳細(xì)信息,官方教程的寫法跟官方發(fā)布的正式版代碼描述的不相同,可能是我理解不夠深入,或者兩者是等價的,這點以后再找時間研究,但這并不影響我們對這一章節(jié)的學(xué)習(xí)。
?
Note:OpenCV提供了多種格式圖像的支持,包括Windows bitmap(bmp),portable image formats (pbm, pgm,ppm) 以及 Sun raster (sr, ras)。關(guān)于其它的格式,有JPEG (jpeg, jpg, jpe),JPEG 2000,TIFF 文件 (tiff, tif),portable network graphics (png),


還有openEXR格式,如果OpenCV是自己打包的話,讀取這些格式需要有插件支持,如果是官方提供的庫,則不需再添加插件。
?
?
?
在檢查圖像是否讀取成功之后,我們需要顯示讀入的圖像,因此,我們采用namedWindow函數(shù)來創(chuàng)建一個OpenCV窗口,該函數(shù)的定義如下:
?
CV_EXPORTS_W void namedWindow(const string& winname, int flags = WINDOW_AUTOSIZE);
?
為此,我們需要指定該窗口的名稱(窗口標(biāo)識符, window identifier)以及如何處理窗口大小。①窗口標(biāo)識符需要唯一指定,如果已經(jīng)存在一個該名字的窗口,則此函數(shù)不進(jìn)行任何處理;②flags參數(shù)目前只支持CV_WINDOW_AUTOSIZE,在highgui_c.h中,OpenCV定義了


CV_WINDOW_AUTOSIZE= 0×00000001,如果設(shè)置該參數(shù),則表示顯示的時候窗口自適應(yīng)于需要顯示的圖像,而且不能修改窗口大小,如果不設(shè)置(省略此參數(shù)),可以通過代碼進(jìn)行修改;③如果將OpenCV用于Qt后端開發(fā),該參數(shù)還支持其它值,具體可查看OpenCV開發(fā)文檔


,這里不再贅述。
?
--------------------------------------------------------------------------------




imshow(“l(fā)ena”, img);
?
--------------------------------------------------------------------------------


imshow用于在我們創(chuàng)建的窗口中顯示需要顯示的圖像,其函數(shù)原型為:
?
void imshow(const string& winname, InputArray mat);
?
第一個參數(shù)winname是指窗口的名稱,也就是窗口標(biāo)識符,第二個參數(shù)mat就是我們要顯示的圖像了。正如我們在namedWindow函數(shù)中所描述的那樣,如果namedWindow指定了參數(shù)CV_WINDOW_AUTOSIZE,則圖像會按原始大小顯示,否則圖像會根據(jù)窗口大小進(jìn)行縮放。




--------------------------------------------------------------------------------




waitKey();
?
--------------------------------------------------------------------------------




這條語句表示等待用戶鍵盤操作,waitKey函數(shù)的函數(shù)原型如下:
?
int waitKey(int delay = 0);
?
我們可以看到,該函數(shù)可包含一個整形參數(shù),不設(shè)置參數(shù)的情況下,默認(rèn)為0,也就是無限制等待。該整數(shù)表示需要等待用戶操作的毫秒數(shù)。
?
2 加載、修改并保存圖像(Load, Modify, and Save an Image)
?
2.1 學(xué)習(xí)目標(biāo)
?
在這一章,我們將學(xué)習(xí):1)加載一副圖像(采用imread函數(shù),同第一章);2)將一副圖像從RGB格式轉(zhuǎn)換成灰度圖(grayscale,采用cvtColor函數(shù));3)保存轉(zhuǎn)換后的圖像到磁盤上(采用imwrite函數(shù))。
?
2.2 源代碼
?
<pre lang=”cpp”>
?
#include “StdAfx.h”
?
#include <cv.h>
?
#include <highgui.h>
?
#include <string>
?
?
?
using namespace cv;
?
using namespace std;
?
?
?
int main()
?
{
?
? ? ? ? ?char* imageName = “l(fā)ena.jpg”;
?
? ? ? ? ?Mat image = imread(imageName, 1);
?
?
?
? ? ? ? ?if (!image.data)
?
? ? ? ? ?{
?
? ? ? ? ? ? ? ? ? ?cout<<”Could not open or find the image!”<<endl;
?
? ? ? ? ? ? ? ? ? ?return -1;
?
? ? ? ? ?}
?
?
?
? ? ? ? ?Mat gray_image;
?
? ? ? ? ?String grayImageName = “l(fā)ena_gray”;
?
?
?
? ? ? ? ?cvtColor(image,gray_image,CV_RGB2GRAY);//將RGB圖像轉(zhuǎn)換成灰度圖像
?
? ? ? ? ?imwrite(“../../lena_gray.jpg”,gray_image);//保存圖像
?
?
?
? ? ? ? ?namedWindow(imageName, CV_WINDOW_AUTOSIZE);//創(chuàng)建用于顯示元圖像窗口
?
? ? ? ? ?namedWindow(grayImageName,CV_WINDOW_AUTOSIZE);//創(chuàng)建用于顯示轉(zhuǎn)換后圖像窗口
?
?
?
? ? ? ? ?imshow(imageName,image);
?
? ? ? ? ?imshow(“grayImageName”, gray_image);
?
?
?
? ? ? ? ?waitKey(0);
?
? ? ? ? ?return 0;
?
}
?
</pre>
?
2.3 源碼詳解
?
有了第一章的基礎(chǔ)后,再來理解本章代碼相對就很容易,在這一節(jié),關(guān)于imread函數(shù)的使用則不再贅述,下面給cvtColor和imwrite來一個特寫。
?


--------------------------------------------------------------------------------




cvtColor(image,gray_image,CV_RGB2GRAY);// 將RGB圖像轉(zhuǎn)換成灰度圖像
?


--------------------------------------------------------------------------------




cvtColor函數(shù)用于將圖像從一個顏色空間轉(zhuǎn)換到另一個顏色空間,其函數(shù)原型為:
?
void cvtColor( InputArray src, OutputArray dst, int code, int dstCn=0 );
?
參數(shù)src:是指需要轉(zhuǎn)化的圖像,可以是8位或16位等的無符號型或者是單精度浮點型(Single-Precision Floating-Point);
?
參數(shù)dst:與原始圖像具有相同大小和深度的目標(biāo)圖像;
?
參數(shù)code:顏色空間轉(zhuǎn)換代碼;
?
參數(shù)dstCn:目標(biāo)圖像的通道數(shù),如果該參數(shù)為0,則通道數(shù)可由src和code自動獲得;
?
對于一個原圖像或目標(biāo)圖像是RGB的轉(zhuǎn)換,我們需要詳細(xì)地指定通道的順序(RGB or BGR)。我們注意到,OpenCV默認(rèn)情況下的顏色格式一般是指RGB,但實際上卻進(jìn)行了一個反轉(zhuǎn)變成BGR,因此對一個標(biāo)準(zhǔn)的24位圖像來說,其第一個字節(jié)為8位的藍(lán)色部分(Blue?


Component),其次是綠色,接著是紅色,再然后就是第二個像素,同樣以BGR的通道順序排列。
?
常規(guī)的RGB通道的值的范圍如下:
?
對于8位無符號精度圖像(CV_8U Images),其范圍是0~255
?
對于16位無符號精度圖像(CV_16U Images),其范圍是0~65535
?
對于32位單精度浮點型圖像(CV_32F Images),其范圍是0~1
?
在線性變換的情況下,我們可以不用考慮其通道的取值范圍,但對于非線性變換(Non-Linear Transformation),一個RGB輸入圖像應(yīng)該先做規(guī)格化處理(Normalized),以便得到一個合適的范圍來獲取正確的結(jié)果。比如對于一個RGB顏色空間到LUV顏色空間的變換,如


果我們需要將一副8位圖像轉(zhuǎn)換到一副32位的浮點型精度圖像而不進(jìn)行任何縮放,也就是說,我們將一個從0~255的范圍替換成0~1的范圍,那么我們首先要將圖像按比例縮小(Scale the Image Down):
?
img *= 1./255;
?
cvtColor(img, img, CV_BGR2Luv);
?
如果我們采用8位的圖像進(jìn)行轉(zhuǎn)換,該過程中可能會有信息的丟失,盡管在一般的應(yīng)用中,這種丟失并不明顯(Noticeable),但我們強(qiáng)烈建議使用一個32位的圖像或者在變換之前先轉(zhuǎn)換成32位。
?
備注:關(guān)于參數(shù)code的跟多取值,可以參見OpenCV 2.4.0官方文檔:cvtColor函數(shù)指南及使用方法
?
--------------------------------------------------------------------------------


?
?
imwrite(“../../lena_gray.jpg”,gray_image);// 保存圖像
?


--------------------------------------------------------------------------------




imwrite函數(shù)用于將圖像保存到指定的文件,其函數(shù)原型為:
?
bool imwrite(const string& filename, InputArray image, const vector<int>& params=vector<int>())
?
參數(shù)filename:指代需要保存文件的名稱
?
參數(shù)image:需要保存的圖像
?
參數(shù)params:保存至指定格式圖像格式時的參數(shù)設(shè)置
?
關(guān)于params參數(shù)的取值如下:
?
對JPEG圖像,它表示圖像質(zhì)量(CV_IMWRITE_JPEG_QUALITY),取值從1~100,值越大質(zhì)量越高,默認(rèn)為95;
?
對PNG圖像,它表示圖像壓縮率(CV_IMWRITE_PNG_COMPRESSION),取值從0~9,值越大壓縮率越大壓縮時間越長,默認(rèn)值為3;
?
對PPM,PGM或PBM,它是一個二進(jìn)制標(biāo)識(CV_IMWRITE_PXM_BINARY),取值為0或1,默認(rèn)為1。
?
有關(guān)于該函數(shù)及參數(shù)params的詳細(xì)信息及應(yīng)用可參見開發(fā)文檔:imwrite函數(shù)指南及使用方法
?


========

圖像縮放--OpenCV cvResize函數(shù)--最近鄰插值---雙線性插值



void cvResize( const CvArr* src, CvArr* dst, int interpolation=CV_INTER_LINEAR ); src輸入圖像.dst輸出圖像.interpolation插值方法:
CV_INTER_NN - 最近鄰插值,
CV_INTER_LINEAR - 雙線性插值 (缺省使用)
CV_INTER_AREA - 使用象素關(guān)系重采樣。當(dāng)圖像縮小時候,該方法可以避免波紋出現(xiàn)。當(dāng)圖像放大時,類似于 CV_INTER_NN 方法..
CV_INTER_CUBIC - 立方插值.
函數(shù) cvResize 將圖像 src 改變尺寸得到與 dst 同樣大小。若設(shè)定 ROI,函數(shù)將按常規(guī)支持 ROI.


最近鄰插值:效果(放大4倍)有馬賽克現(xiàn)象




雙線性插值:效果(放大4倍)比最近鄰插值效果好


最近鄰插值和雙線性插值的基本原理


圖像的縮放很好理解,就是圖像的放大和縮小。傳統(tǒng)的繪畫工具中,有一種叫做“放大尺”的繪畫工具,畫家常用它來放大圖畫。當(dāng)然,在計算機(jī)上,我們不再需要用放大尺去放大或縮小圖像了,把這個工作交給程序來完成就可以了。下面就來講講計算機(jī)怎么來放大縮小


圖象;在本文中,我們所說的圖像都是指點陣圖,也就是用一個像素矩陣來描述圖像的方法,對于另一種圖像:用函數(shù)來描述圖像的矢量圖,不在本文討論之列。
越是簡單的模型越適合用來舉例子,我們就舉個簡單的圖像:3X3 的256級灰度圖,也就是高為3個象素,寬也是3個象素的圖像,每個象素的取值可以是 0-255,代表該像素的亮度,255代表最亮,也就是白色,0代表最暗,即黑色。假如圖像的象素矩陣如下圖所示(這


個原始圖把它叫做源圖,Source):
234 ? 38 ? ?22
67 ? ? 44 ? ?12
89 ? ? 65 ? ?63
這個矩陣中,元素坐標(biāo)(x,y)是這樣確定的,x從左到右,從0開始,y從上到下,也是從零開始,這是圖象處理中最常用的坐標(biāo)系,就是這樣一個坐標(biāo):
? ---------------------->X
? |
? |
? |
? |
? |
∨Y
如果想把這副圖放大為 4X4大小的圖像,那么該怎么做呢?那么第一步肯定想到的是先把4X4的矩陣先畫出來再說,好了矩陣畫出來了,如下所示,當(dāng)然,矩陣的每個像素都是未知數(shù),等待著我們?nèi)ヌ畛?#xff08;這個將要被填充的圖的叫做目標(biāo)圖,Destination):
? ? ? ? ?? ? ? ? ?? ? ? ? ?
? ? ? ? ?? ? ? ? ?? ? ? ? ?
? ? ? ? ?? ? ? ? ?? ? ? ? ?
? ? ? ? ?? ? ? ? ?? ? ? ? ??
? ? ? ? ? ? ? ?
? ? ? ? 然后要往這個空的矩陣?yán)锩嫣钪盗?#xff0c;要填的值從哪里來來呢?是從源圖中來,好,先填寫目標(biāo)圖最左上角的象素,坐標(biāo)為(0,0),那么該坐標(biāo)對應(yīng)源圖中的坐標(biāo)可以由如下公式得出: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
srcX=dstX* (srcWidth/dstWidth) , srcY = dstY * (srcHeight/dstHeight)
好了,套用公式,就可以找到對應(yīng)的原圖的坐標(biāo)了(0*(3/4),0*(3/4))=>(0*0.75,0*0.75)=>(0,0)
,找到了源圖的對應(yīng)坐標(biāo),就可以把源圖中坐標(biāo)為(0,0)處的234象素值填進(jìn)去目標(biāo)圖的(0,0)這個位置了。
接下來,如法炮制,尋找目標(biāo)圖中坐標(biāo)為(1,0)的象素對應(yīng)源圖中的坐標(biāo),套用公式:
(1*0.75,0*0.75)=>(0.75,0)
結(jié)果發(fā)現(xiàn),得到的坐標(biāo)里面竟然有小數(shù),這可怎么辦?計算機(jī)里的圖像可是數(shù)字圖像,象素就是最小單位了,象素的坐標(biāo)都是整數(shù),從來沒有小數(shù)坐標(biāo)。這時候采用的一種策略就是采用四舍五入的方法(也可以采用直接舍掉小數(shù)位的方法),把非整數(shù)坐標(biāo)轉(zhuǎn)換成整數(shù),好,那


么按照四舍五入的方法就得到坐標(biāo)(1,0),完整的運算過程就是這樣的:
(1*0.75,0*0.75)=>(0.75,0)=>(1,0)
那么就可以再填一個象素到目標(biāo)矩陣中了,同樣是把源圖中坐標(biāo)為(1,0)處的像素值38填入目標(biāo)圖中的坐標(biāo)。
? ? ? ? ?
依次填完每個象素,一幅放大后的圖像就誕生了,像素矩陣如下所示:
234 ? ?38 ? ? 22 ? ? 22 ?
67 ? ? ?44 ? ? 12 ? ? 12 ?
89 ? ? ?65 ? ? 63 ? ? 63 ?
89 ? ? ?65 ? ? 63 ? ? 63 ?
這種放大圖像的方法叫做最臨近插值算法,這是一種最基本、最簡單的圖像縮放算法,效果也是最不好的,放大后的圖像有很嚴(yán)重的馬賽克,縮小后的圖像有很嚴(yán)重的失真;效果不好的根源就是其簡單的最臨近插值方法引入了嚴(yán)重的圖像失真,比如,當(dāng)由目標(biāo)圖的坐標(biāo)


反推得到的源圖的的坐標(biāo)是一個浮點數(shù)的時候,采用了四舍五入的方法,直接采用了和這個浮點數(shù)最接近的象素的值,這種方法是很不科學(xué)的,當(dāng)推得坐標(biāo)值為 0.75的時候,不應(yīng)該就簡單的取為1,既然是0.75,比1要小0.25 ,比0要大0.75 ,那么目標(biāo)象素值其實應(yīng)該根


據(jù)這個源圖中虛擬的點四周的四個真實的點來按照一定的規(guī)律計算出來的,這樣才能達(dá)到更好的縮放效果。雙線型內(nèi)插值算法就是一種比較好的圖像縮放算法,它充分的利用了源圖中虛擬點四周的四個真實存在的像素值來共同決定目標(biāo)圖中的一個像素值,因此縮放效果


比簡單的最鄰近插值要好很多。
雙線性內(nèi)插值算法描述如下:
  對于一個目的像素,設(shè)置坐標(biāo)通過反向變換得到的浮點坐標(biāo)為(i+u,j+v) (其中i、j均為浮點坐標(biāo)的整數(shù)部分,u、v為浮點坐標(biāo)的小數(shù)部分,是取值[0,1)區(qū)間的浮點數(shù)),則這個像素得值 f(i+u,j+v) 可由原圖像中坐標(biāo)為 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所對


應(yīng)的周圍四個像素的值決定,即:
  f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1) ? ? ? ? ? ? ? ? ? ? ? ? ?公式1
其中f(i,j)表示源圖像(i,j)處的的像素值,以此類推。
比如,象剛才的例子,現(xiàn)在假如目標(biāo)圖的象素坐標(biāo)為(1,1),那么反推得到的對應(yīng)于源圖的坐標(biāo)是(0.75 , 0.75), 這其實只是一個概念上的虛擬象素,實際在源圖中并不存在這樣一個象素,那么目標(biāo)圖的象素(1,1)的取值不能夠由這個虛擬象素來決定,而只能由源


圖的這四個象素共同決定:(0,0)(0,1)(1,0)(1,1),而由于(0.75,0.75)離(1,1)要更近一些,那么(1,1)所起的決定作用更大一些,這從公式1中的系數(shù)uv=0.75×0.75就可以體現(xiàn)出來,而(0.75,0.75)離(0,0)最遠(yuǎn),所以(0,0)所起的決定作用


就要小一些,公式中系數(shù)為(1-u)(1-v)=0.25×0.25也體現(xiàn)出了這一特點。
原理參考link:http://blog.csdn.net/andrew659/article/details/4818988
OpenCV代碼:scale是放縮比例


點擊(此處)折疊或打開
#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <cmath>
using namespace std;
using namespace cv;


int main(int argc ,char ** argv)
{
? ? IplImage *scr=0;
? ? IplImage *dst=0;
? ? double scale=4;
? ? CvSize dst_cvsize;
? ? if (argc==2&&(scr=cvLoadImage(argv[1],-1))!=0)
? ? {
? ? ? ? dst_cvsize.width=(int)(scr->width*scale);
? ? ? ? dst_cvsize.height=(int)(scr->height*scale);
? ? ? ? dst=cvCreateImage(dst_cvsize,scr->depth,scr->nChannels);


? ? ? ? cvResize(scr,dst,CV_INTER_NN);//
// ? ? ? ? ? ? CV_INTER_NN - 最近鄰插值,
// ? ? ? ? ? ? CV_INTER_LINEAR - 雙線性插值 (缺省使用)
// ? ? ? ? ? ? CV_INTER_AREA - 使用象素關(guān)系重采樣。當(dāng)圖像縮小時候,該方法可以避免波紋出現(xiàn)。
? ? ? ? ?/*當(dāng)圖像放大時,類似于 CV_INTER_NN 方法..*/
// ? ? ? ? ? ? CV_INTER_CUBIC - 立方插值.


? ? ? ? cvNamedWindow("scr",CV_WINDOW_AUTOSIZE);
? ? ? ? cvNamedWindow("dst",CV_WINDOW_AUTOSIZE);
? ? ? ? cvShowImage("scr",scr);
? ? ? ? cvShowImage("dst",dst);
? ? ? ? cvWaitKey();
? ? ? ? cvReleaseImage(&scr);
? ? ? ? cvReleaseImage(&dst);
? ? ? ? cvDestroyWindow("scr");
? ? ? ? cvDestroyWindow("dst");
? ? }
? ? return 0;
}
========

opencv初體驗-圖片濾鏡效果



我參考了http://blog.csdn.net/yangtrees/article/details/9116337的代碼,


稍作修改,將其變成一個小工具,可將圖片加“懷舊色”濾鏡保存輸出。


不說廢話,直接上代碼。


#include <opencv/cv.h>
#include <opencv/highgui.h>


using namespace cv;
using namespace std;




int main(int argc, char ** argv)
{
? ? // input args check
? ? if(argc < 3){
? ? ? ? printf("please input args.\n");
? ? ? ? printf("e.g. : ./test infilepath outfilepath \n");
? ? ? ? return 0;
? ? }
? ??
? ? char * input = argv[1];
? ? char * output = argv[2];
? ??
? ? printf("input: %s, output: %s\n", input, output);


? ? Mat src = imread(input, 1);


? ? int width=src.cols;
? ? int heigh=src.rows;
? ? RNG rng;
? ? Mat img(src.size(),CV_8UC3);
? ? for (int y=0; y<heigh; y++)
? ? {
? ? ? ? uchar* P0 = src.ptr<uchar>(y);
? ? ? ? uchar* P1 = img.ptr<uchar>(y);
? ? ? ? for (int x=0; x<width; x++)
? ? ? ? {
? ? ? ? ? ? float B=P0[3*x];
? ? ? ? ? ? float G=P0[3*x+1];
? ? ? ? ? ? float R=P0[3*x+2];
? ? ? ? ? ? float newB=0.272*R+0.534*G+0.131*B;
? ? ? ? ? ? float newG=0.349*R+0.686*G+0.168*B;
? ? ? ? ? ? float newR=0.393*R+0.769*G+0.189*B;
? ? ? ? ? ? if(newB<0)newB=0;
? ? ? ? ? ? if(newB>255)newB=255;
? ? ? ? ? ? if(newG<0)newG=0;
? ? ? ? ? ? if(newG>255)newG=255;
? ? ? ? ? ? if(newR<0)newR=0;
? ? ? ? ? ? if(newR>255)newR=255;
? ? ? ? ? ? P1[3*x] = (uchar)newB;
? ? ? ? ? ? P1[3*x+1] = (uchar)newG;
? ? ? ? ? ? P1[3*x+2] = (uchar)newR;
? ? ? ? }


? ? }
? ? //imshow("out",img);
? ? waitKey();
? ? imwrite(output,img);
}


編譯時需要注意一下,需要加上`pkg-config opencv --libs --cflags opencv`


例如:g++ -o test opencvtest.cpp `pkg-config opencv --libs --cflags opencv`


OK,編譯正常。


從網(wǎng)上下個圖片,做個測試。


看下效果,還不錯。


原圖:


處理后:


========

用opencv將圖片變成水波紋效果



將一幅圖片變成水波紋效果。我在網(wǎng)上找到一份源碼,參考之下,順著思路用opencv2重寫之。


思路如下:


1.將圖片中的坐標(biāo)點(x,y)換成極坐標(biāo),有現(xiàn)成的函數(shù)。


2.極坐標(biāo)下,用三角函數(shù)算出新半徑。


3.在新半徑之下,轉(zhuǎn)換成新的坐標(biāo)(x 0 ,y 0 ),如果新坐標(biāo)是小數(shù),用雙線性插值的方法處理。


關(guān)鍵代碼如下:


其中一些變量聲明如下:


Mat imageInfo;//原圖片
? ? ? ? int imageWidth;
? ? ? ? int imageHeight;
? ? ? ? int imageX;//圖像中心點的橫坐標(biāo)
? ? ? ? int imageY;//圖像中心點的縱坐標(biāo)
? ? ? ? float A;//波紋幅度
? ? ? ? float B;//波紋周期 ? Asin(Bx);
? ? ? ? int imageChannels;//通道數(shù)
? ? ? ? Mat imageWater;//轉(zhuǎn)換后的圖片
? ? ? ? void reCalcAB(int i,int j,float &a,float &b);//坐標(biāo)轉(zhuǎn)換
? ? ? ? uchar BLIP(float a,float b,int k);
? ? ? ? //k為通道數(shù),值為-1為單通道,灰度圖
?void imagetest::imageprocess()
?{
? ? ?imageInfo.copyTo(imageWater);
?
? ? ?float a;
? ? ?float b;//臨時坐標(biāo)
?
? ? ?for(int i=0;i<imageHeight-1;i++)
? ? ?{
? ? ? ? ?uchar *Data = imageWater.ptr<uchar>(i);
? ? ? ? ?for(int j=0;j<imageWidth-1;j++)
? ? ? ? ?{
? ? ? ? ? ? ?reCalcAB(i,j,a,b);
? ? ? ? ? ? ?if(imageChannels == 1)//彩色與灰度圖像要單獨處理,否則
? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ? ? //會出現(xiàn)橢圓的情況
? ? ? ? ? ? ? ? ?*(Data+j) = BLIP(a,b,-1);//-1指灰度圖
? ? ? ? ? ? ?}
? ? ? ? ? ? ?else if(imageChannels == 3)
? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?for(int k = 0;k<imageChannels;k++)
? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ?*(Data+j*imageChannels+k)= BLIP(a,b,k);
? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ?}
? ? ? ? ?}
? ? ?}
?}
reCalcAB是坐標(biāo)轉(zhuǎn)換函數(shù):


?void imagetest::reCalcAB(int i,int j,float &a,float &b)
?{
? ? ?float y0 = (float)(i-imageY);
? ? ?float x0 = (float)(j-imageX);//(i,j)相對于原點的坐標(biāo)
? ? ?float theta0 = atan2f(y0,x0);//轉(zhuǎn)化成角坐標(biāo)
? ? ?float r0 = sqrtf(x0*x0+y0*y0);//初始半徑
?
? ? ?float r1 = r0+ A*imageWidth*0.01*sin(B*0.1*r0);//計算新的半徑
? ? ?a = imageX + r1*cos(theta0);
? ? ?b = imageY + r1*sin(theta0);//轉(zhuǎn)換后的坐標(biāo)
? ? ?if(a>imageWidth)
? ? ? ? ?a = imageWidth-1;
? ? ?else if(a<0)
? ? ? ? ?a = 0; ? ? ? ? ? ? ? ?//超出邊界的處理
? ? ?if(b>imageHeight)
? ? ? ? ?b = imageHeight-1;
? ? ?else if(b<0)
? ? ? ? ?b = 0;
?}
雙線性插值函數(shù):(這個方法看著很高級,實際很簡單。仔細(xì)看代碼就明白怎么回事情了)


?uchar imagetest::BLIP(float a,float b,int k)
?{
? ? ?uchar newData;//保存結(jié)果
? ? ?uchar DataTemp1;
? ? ?uchar DataTemp2;//兩個中間變量
? ? ?int x[2];
? ? ?int y[2];//存儲周圍四個點。
?
? ? ?x[0] = (int)a;
? ? ?y[0] = (int)b;
? ? ?x[1] = x[0]+1;
? ? ?y[1] = y[0]+1;//(a,b)周圍四個整點坐標(biāo)
? ? ?//取值
? ? ?uchar *data1 = imageWater.data + y[0]*imageWater.step + x[0]*imageChannels;
? ? ?uchar *data2 = imageWater.data + y[0]*imageWater.step + x[1]*imageChannels;
? ? ?uchar *data3 = imageWater.data + y[1]*imageWater.step + x[0]*imageChannels;
? ? ?uchar *data4 = imageWater.data + y[1]*imageWater.step + x[1]*imageChannels;
? ? ?if(k!=-1)//如果是彩色,轉(zhuǎn)換一下
? ? ?{
? ? ? ? ?data1 += k;
? ? ? ? ?data2 += k;
? ? ? ? ?data3 += k;
? ? ? ? ?data4 += k;
? ? ?}
?
? ? ?if((fabsf(a-x[0])<0.00001) && (fabsf(b-y[0])<0.00001))//整點,直接返回
? ? ?{
? ? ? ? ?newData = *data1;
? ? ? ? ?return newData;
? ? ?}
?
? ? ?float dx = fabsf(a-x[0]);//x軸的比例
? ? ?float dy = fabsf(b-y[0]);//y軸的比例
?
? ? ?DataTemp1 = (*data1)*(1.0-dx) + (*data2)*dx;
? ? ?DataTemp2 = (*data3)*(1.0-dx) + (*data4)*dx;
? ? ?newData = DataTemp1*(1.0-dy) + DataTemp2*dy;//核心插值過程
?
? ? ?return newData;
?}


這個效果看起來倒是不錯,總感覺不是那么真實。


而且,這個程序有嚴(yán)重的問題。如果我換一張圖片,重新設(shè)置 A和B的參數(shù)


就會出現(xiàn)如下的效果:




中間水平方向出現(xiàn)了明顯的一條橫線。


目前還沒有解決的問題主要就是這條橫線,然后就是怎么樣才能使得水波紋看起來更真實。我想把用一張圖片做成視頻,不知道這個效果最后做出來是個什么樣子。


如果是坐標(biāo)轉(zhuǎn)換出錯了的話,理論上來說應(yīng)該會水平、豎直都應(yīng)該出現(xiàn)一條直線,現(xiàn)在只有水平方向有一條直線。


========

在OpenCV中實現(xiàn)特效之浮雕,雕刻和褶皺



下面代碼的基礎(chǔ)是對圖像像素的訪問。


實現(xiàn)浮雕和雕刻的代碼是統(tǒng)一的,如下


#include <cv.h> ?
#include <highgui.h> ?
#pragma comment( lib, "cv.lib" ) ?
#pragma comment( lib, "cxcore.lib" ) ?
#pragma comment( lib, "highgui.lib" ) ?
int main() ?
{ ?
? ? IplImage *org=cvLoadImage("1.jpg",1); ?
? ? IplImage *image=cvCloneImage(org); ?
? ? int width=image->width; ?
? ? int height=image->height; ?
? ? int step=image->widthStep; ?
? ? int channel=image->nChannels; ?
? ? uchar* data=(uchar *)image->imageData; ?
? ? for(int i=0;i<width-1;i++) ?
? ? { ?
? ? ? ? for(int j=0;j<height-1;j++) ?
? ? ? ? { ?
? ? ? ? ? ? for(int k=0;k<channel;k++) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? int temp = data[(j+1)*step+(i+1)*channel+k]-data[j*step+i*channel+k]+128;//浮雕 ?
? ? ? ? ? ? ? ? //int temp = data[j*step+i*channel+k]-data[(j+1)*step+(i+1)*channel+k]+128;//雕刻 ?
? ? ? ? ? ? ? ? if(temp>255) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? data[j*step+i*channel+k]=255; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? else if(temp<0) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? data[j*step+i*channel+k]=0; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? else ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? data[j*step+i*channel+k]=temp; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? } ?
? ? cvNamedWindow("original",1); ?
? ? cvShowImage("original",org); ?
? ? cvNamedWindow("image",1); ?
? ? cvShowImage("image",image); ?
? ? cvWaitKey(0); ??
? ? cvDestroyAllWindows(); ?
? ? cvReleaseImage(&image); ?
? ? cvReleaseImage(&org); ?
? ? return 0; ?
} ?
原圖為


浮雕效果圖如下


雕刻效果圖如下


下面是實現(xiàn)圖像褶皺的代碼,效果不是太好,結(jié)構(gòu)過渡不平滑,以后再改進(jìn)一下。希望能做到波浪化。


#include <cv.h> ?
#include <highgui.h> ?
#pragma comment( lib, "cv.lib" ) ?
#pragma comment( lib, "cxcore.lib" ) ?
#pragma comment( lib, "highgui.lib" ) ?
int main() ?
{ ?
? ? IplImage *org=cvLoadImage("lena.jpg",1); ?
? ? IplImage *image=cvCloneImage(org); ?
? ? int width=image->width; ?
? ? int height=image->height; ?
? ? int step=image->widthStep; ?
? ? int channel=image->nChannels; ?
? ? uchar* data=(uchar *)image->imageData; ?
? ? int sign=-1; ?
? ? for(int i=0;i<height;i++) ?
? ? { ? ??
? ? ? ? int cycle=10; ?
? ? ? ? int margin=(i%cycle); ?
? ? ? ? if((i/cycle)%2==0) ?
? ? ? ? { ?
? ? ? ? ? ? sign=-1; ?
? ? ? ? } ?
? ? ? ? else ?
? ? ? ? { ?
? ? ? ? ? ? sign=1; ?
? ? ? ? } ?
? ? ? ? if(sign==-1) ?
? ? ? ? { ? ??
? ? ? ? ? ? margin=cycle-margin; ?
? ? ? ? ? ? for(int j=0;j<width-margin;j++) ?
? ? ? ? ? ? { ? ? ? ? ? ??
? ? ? ? ? ? ? ? for(int k=0;k<channel;k++) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? data[i*step+j*channel+k]=data[i*step+(j+margin)*channel+k]; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? ? ? else if(sign==1) ?
? ? ? ? { ? ? ? ??
? ? ? ? ? ? for(int j=0;j<width-margin;j++) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? for(int k=0;k<channel;k++) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? data[i*step+j*channel+k]=data[i*step+(j+margin)*channel+k]; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? } ?
? ? ? ? } ? ??
? ? } ?
? ? cvNamedWindow("original",1); ?
? ? cvShowImage("original",org); ?
? ? cvNamedWindow("image",1); ?
? ? cvShowImage("image",image); ?
? ? cvSaveImage("image.jpg",image); ?
? ? cvWaitKey(0); ??
? ? cvDestroyAllWindows(); ?
? ? cvReleaseImage(&image); ?
? ? cvReleaseImage(&org); ?
? ? return 0; ?
} ?
測試圖是標(biāo)準(zhǔn)的lena圖,效果圖如下


========

基于GraphCuts圖割算法的圖像分割----OpenCV代碼與實現(xiàn)

圖切算法是組合圖論的經(jīng)典算法之一。近年來,許多學(xué)者將其應(yīng)用到圖像和視頻分割中,取得了很好的效果。本文簡單介紹了圖切算法和交互式圖像分割技術(shù),以及圖切算法在交互式圖像分割中的應(yīng)用。
?
圖像分割指圖像分成各具特性的區(qū)域并提取出感興趣目標(biāo)的技術(shù)和過程,它是由圖像處理到圖像分析的關(guān)鍵步驟,是一種基本的計算機(jī)視覺技術(shù)。只有在圖像分割的基礎(chǔ)上才能對目標(biāo)進(jìn)行特征提取和參數(shù)測量,使得更高層的圖像分析和理解成為可能。因此對圖像分割方


法的研究具有十分重要的意義。
?
圖像分割技術(shù)的研究已有幾十年的歷史,但至今人們并不能找到通用的方法能夠適合于所有類型的圖像。常用的圖像分割技術(shù)可劃分為四類:特征閾值或聚類、邊緣檢測、區(qū)域生長或區(qū)域提取。雖然這些方法分割灰度圖像效果較好,但用于彩色圖像的分割往往達(dá)不到理


想的效果。
?
交互式圖像分割是指,首先由用戶以某種交互手段指定圖像的部分前景與部分背景,然后算法以用戶的輸入作為分割的約束條件自動地計算出滿足約束條件下的最佳分割。典型的交互手段包括用一把畫刷在前景和背景處各畫幾筆(如[1][4]等)以及在前景的周圍畫一個


方框(如[2])等。
?
基于圖切算法的圖像分割技術(shù)是近年來國際上圖像分割領(lǐng)域的一個新的研究熱點。該類方法將圖像映射為賦權(quán)無向圖,把像素視作節(jié)點,利用最小切割得到圖像的最佳分割。
?
?
Graph Cut[1]算法是一種直接基于圖切算法的圖像分割技術(shù)。它僅需要在前景和背景處各畫幾筆作為輸入,算法將建立各個像素點與前景背景相似度的賦權(quán)圖,并通過求解最小切割區(qū)分前景和背景。
?
? ? ? ?Grabcut[2]算法方法的用戶交互量很少,僅僅需要指定一個包含前景的矩形,隨后用基于圖切算法在圖像中提取前景。
?
? ? ? ?Lazy Snapping[4]系統(tǒng)則是對[1]的改進(jìn)。通過預(yù)計算和聚類技術(shù),該方法提供了一個即時反饋的平臺,方便用戶進(jìn)行交互分割。


文檔說明:
http://download.csdn.net/detail/wangyaninglm/8484301
?
代碼實現(xiàn)效果:


graphcuts代碼:
http://download.csdn.net/detail/wangyaninglm/8484243
?
ICCV'2001論文"Interactive graph cuts for optimal boundary and region segmentation of objects in N-D images"。
Graph Cut方法是基于顏色統(tǒng)計采樣的方法,因此對前背景相差較大的圖像效果較佳。
同時,比例系數(shù)lambda的調(diào)節(jié)直接影響到最終的分割效果。
?
grabcut代碼:
?
// Grabcut.cpp : 定義控制臺應(yīng)用程序的入口點。 ?
// ?
??
#include "stdafx.h" ?
??
#include "opencv2/highgui/highgui.hpp" ?
#include "opencv2/imgproc/imgproc.hpp" ?
??
#include <iostream> ?
??
#include "ComputeTime.h" ?
#include "windows.h" ?
??
using namespace std; ?
using namespace cv; ?
??
static void help() ?
{ ?
? ? cout << "\nThis program demonstrates GrabCut segmentation -- select an object in a region\n" ?
? ? ? ? "and then grabcut will attempt to segment it out.\n" ?
? ? ? ? "Call:\n" ?
? ? ? ? "./grabcut <image_name>\n" ?
? ? ? ? "\nSelect a rectangular area around the object you want to segment\n" << ?
? ? ? ? "\nHot keys: \n" ?
? ? ? ? "\tESC - quit the program\n" ?
? ? ? ? "\tr - restore the original image\n" ?
? ? ? ? "\tn - next iteration\n" ?
? ? ? ? "\n" ?
? ? ? ? "\tleft mouse button - set rectangle\n" ?
? ? ? ? "\n" ?
? ? ? ? "\tCTRL+left mouse button - set GC_BGD pixels\n" ?
? ? ? ? "\tSHIFT+left mouse button - set CG_FGD pixels\n" ?
? ? ? ? "\n" ?
? ? ? ? "\tCTRL+right mouse button - set GC_PR_BGD pixels\n" ?
? ? ? ? "\tSHIFT+right mouse button - set CG_PR_FGD pixels\n" << endl; ?
} ?
??
const Scalar RED = Scalar(0,0,255); ?
const Scalar PINK = Scalar(230,130,255); ?
const Scalar BLUE = Scalar(255,0,0); ?
const Scalar LIGHTBLUE = Scalar(255,255,160); ?
const Scalar GREEN = Scalar(0,255,0); ?
??
const int BGD_KEY = CV_EVENT_FLAG_CTRLKEY; ?//Ctrl鍵 ?
const int FGD_KEY = CV_EVENT_FLAG_SHIFTKEY; //Shift鍵 ?
??
static void getBinMask( const Mat& comMask, Mat& binMask ) ?
{ ?
? ? if( comMask.empty() || comMask.type()!=CV_8UC1 ) ?
? ? ? ? CV_Error( CV_StsBadArg, "comMask is empty or has incorrect type (not CV_8UC1)" ); ?
? ? if( binMask.empty() || binMask.rows!=comMask.rows || binMask.cols!=comMask.cols ) ?
? ? ? ? binMask.create( comMask.size(), CV_8UC1 ); ?
? ? binMask = comMask & 1; ?//得到mask的最低位,實際上是只保留確定的或者有可能的前景點當(dāng)做mask ?
} ?
??
class GCApplication ?
{ ?
public: ?
? ? enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 }; ?
? ? static const int radius = 2; ?
? ? static const int thickness = -1; ?
??
? ? void reset(); ?
? ? void setImageAndWinName( const Mat& _image, const string& _winName ); ?
? ? void showImage() const; ?
? ? void mouseClick( int event, int x, int y, int flags, void* param ); ?
? ? int nextIter(); ?
? ? int getIterCount() const { return iterCount; } ?
private: ?
? ? void setRectInMask(); ?
? ? void setLblsInMask( int flags, Point p, bool isPr ); ?
??
? ? const string* winName; ?
? ? const Mat* image; ?
? ? Mat mask; ?
? ? Mat bgdModel, fgdModel; ?
??
? ? uchar rectState, lblsState, prLblsState; ?
? ? bool isInitialized; ?
??
? ? Rect rect; ?
? ? vector<Point> fgdPxls, bgdPxls, prFgdPxls, prBgdPxls; ?
? ? int iterCount; ?
}; ?
??
/*給類的變量賦值*/ ?
void GCApplication::reset() ?
{ ?
? ? if( !mask.empty() ) ?
? ? ? ? mask.setTo(Scalar::all(GC_BGD)); ?
? ? bgdPxls.clear(); fgdPxls.clear(); ?
? ? prBgdPxls.clear(); ?prFgdPxls.clear(); ?
??
? ? isInitialized = false; ?
? ? rectState = NOT_SET; ? ?//NOT_SET == 0 ?
? ? lblsState = NOT_SET; ?
? ? prLblsState = NOT_SET; ?
? ? iterCount = 0; ?
} ?
??
/*給類的成員變量賦值而已*/ ?
void GCApplication::setImageAndWinName( const Mat& _image, const string& _winName ?) ?
{ ?
? ? if( _image.empty() || _winName.empty() ) ?
? ? ? ? return; ?
? ? image = &_image; ?
? ? winName = &_winName; ?
? ? mask.create( image->size(), CV_8UC1); ?
? ? reset(); ?
} ?
??
/*顯示4個點,一個矩形和圖像內(nèi)容,因為后面的步驟很多地方都要用到這個函數(shù),所以單獨拿出來*/ ?
void GCApplication::showImage() const ?
{ ?
? ? if( image->empty() || winName->empty() ) ?
? ? ? ? return; ?
??
? ? Mat res; ?
? ? Mat binMask; ?
? ? if( !isInitialized ) ?
? ? ? ? image->copyTo( res ); ?
? ? else ?
? ? { ?
? ? ? ? getBinMask( mask, binMask ); ?
? ? ? ? image->copyTo( res, binMask ); ?//按照最低位是0還是1來復(fù)制,只保留跟前景有關(guān)的圖像,比如說可能的前景,可能的背景 ?
? ? } ?
??
? ? vector<Point>::const_iterator it; ?
? ? /*下面4句代碼是將選中的4個點用不同的顏色顯示出來*/ ?
? ? for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it ) ?//迭代器可以看成是一個指針 ?
? ? ? ? circle( res, *it, radius, BLUE, thickness ); ?
? ? for( it = fgdPxls.begin(); it != fgdPxls.end(); ++it ) ?//確定的前景用紅色表示 ?
? ? ? ? circle( res, *it, radius, RED, thickness ); ?
? ? for( it = prBgdPxls.begin(); it != prBgdPxls.end(); ++it ) ?
? ? ? ? circle( res, *it, radius, LIGHTBLUE, thickness ); ?
? ? for( it = prFgdPxls.begin(); it != prFgdPxls.end(); ++it ) ?
? ? ? ? circle( res, *it, radius, PINK, thickness ); ?
??
? ? /*畫矩形*/ ?
? ? if( rectState == IN_PROCESS || rectState == SET ) ?
? ? ? ? rectangle( res, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2); ?
??
? ? imshow( *winName, res ); ?
} ?
??
/*該步驟完成后,mask圖像中rect內(nèi)部是3,外面全是0*/ ?
void GCApplication::setRectInMask() ?
{ ?
? ? assert( !mask.empty() ); ?
? ? mask.setTo( GC_BGD ); ? //GC_BGD == 0 ?
? ? rect.x = max(0, rect.x); ?
? ? rect.y = max(0, rect.y); ?
? ? rect.width = min(rect.width, image->cols-rect.x); ?
? ? rect.height = min(rect.height, image->rows-rect.y); ?
? ? (mask(rect)).setTo( Scalar(GC_PR_FGD) ); ? ?//GC_PR_FGD == 3,矩形內(nèi)部,為可能的前景點 ?
} ?
??
void GCApplication::setLblsInMask( int flags, Point p, bool isPr ) ?
{ ?
? ? vector<Point> *bpxls, *fpxls; ?
? ? uchar bvalue, fvalue; ?
? ? if( !isPr ) //確定的點 ?
? ? { ?
? ? ? ? bpxls = &bgdPxls; ?
? ? ? ? fpxls = &fgdPxls; ?
? ? ? ? bvalue = GC_BGD; ? ?//0 ?
? ? ? ? fvalue = GC_FGD; ? ?//1 ?
? ? } ?
? ? else ? ?//概率點 ?
? ? { ?
? ? ? ? bpxls = &prBgdPxls; ?
? ? ? ? fpxls = &prFgdPxls; ?
? ? ? ? bvalue = GC_PR_BGD; //2 ?
? ? ? ? fvalue = GC_PR_FGD; //3 ?
? ? } ?
? ? if( flags & BGD_KEY ) ?
? ? { ?
? ? ? ? bpxls->push_back(p); ?
? ? ? ? circle( mask, p, radius, bvalue, thickness ); ? //該點處為2 ?
? ? } ?
? ? if( flags & FGD_KEY ) ?
? ? { ?
? ? ? ? fpxls->push_back(p); ?
? ? ? ? circle( mask, p, radius, fvalue, thickness ); ? //該點處為3 ?
? ? } ?
} ?
??
/*鼠標(biāo)響應(yīng)函數(shù),參數(shù)flags為CV_EVENT_FLAG的組合*/ ?
void GCApplication::mouseClick( int event, int x, int y, int flags, void* ) ?
{ ?
? ? // TODO add bad args check ?
? ? switch( event ) ?
? ? { ?
? ? case CV_EVENT_LBUTTONDOWN: // set rect or GC_BGD(GC_FGD) labels ?
? ? ? ? { ?
? ? ? ? ? ? bool isb = (flags & BGD_KEY) != 0, ?
? ? ? ? ? ? ? ? isf = (flags & FGD_KEY) != 0; ?
? ? ? ? ? ? if( rectState == NOT_SET && !isb && !isf )//只有左鍵按下時 ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? rectState = IN_PROCESS; //表示正在畫矩形 ?
? ? ? ? ? ? ? ? rect = Rect( x, y, 1, 1 ); ?
? ? ? ? ? ? } ?
? ? ? ? ? ? if ( (isb || isf) && rectState == SET ) //按下了alt鍵或者shift鍵,且畫好了矩形,表示正在畫前景背景點 ?
? ? ? ? ? ? ? ? lblsState = IN_PROCESS; ?
? ? ? ? } ?
? ? ? ? break; ?
? ? case CV_EVENT_RBUTTONDOWN: // set GC_PR_BGD(GC_PR_FGD) labels ?
? ? ? ? { ?
? ? ? ? ? ? bool isb = (flags & BGD_KEY) != 0, ?
? ? ? ? ? ? ? ? isf = (flags & FGD_KEY) != 0; ?
? ? ? ? ? ? if ( (isb || isf) && rectState == SET ) //正在畫可能的前景背景點 ?
? ? ? ? ? ? ? ? prLblsState = IN_PROCESS; ?
? ? ? ? } ?
? ? ? ? break; ?
? ? case CV_EVENT_LBUTTONUP: ?
? ? ? ? if( rectState == IN_PROCESS ) ?
? ? ? ? { ?
? ? ? ? ? ? rect = Rect( Point(rect.x, rect.y), Point(x,y) ); ? //矩形結(jié)束 ?
? ? ? ? ? ? rectState = SET; ?
? ? ? ? ? ? setRectInMask(); ?
? ? ? ? ? ? assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() ); ?
? ? ? ? ? ? showImage(); ?
? ? ? ? } ?
? ? ? ? if( lblsState == IN_PROCESS ) ? //已畫了前后景點 ?
? ? ? ? { ?
? ? ? ? ? ? setLblsInMask(flags, Point(x,y), false); ? ?//畫出前景點 ?
? ? ? ? ? ? lblsState = SET; ?
? ? ? ? ? ? showImage(); ?
? ? ? ? } ?
? ? ? ? break; ?
? ? case CV_EVENT_RBUTTONUP: ?
? ? ? ? if( prLblsState == IN_PROCESS ) ?
? ? ? ? { ?
? ? ? ? ? ? setLblsInMask(flags, Point(x,y), true); //畫出背景點 ?
? ? ? ? ? ? prLblsState = SET; ?
? ? ? ? ? ? showImage(); ?
? ? ? ? } ?
? ? ? ? break; ?
? ? case CV_EVENT_MOUSEMOVE: ?
? ? ? ? if( rectState == IN_PROCESS ) ?
? ? ? ? { ?
? ? ? ? ? ? rect = Rect( Point(rect.x, rect.y), Point(x,y) ); ?
? ? ? ? ? ? assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() ); ?
? ? ? ? ? ? showImage(); ? ?//不斷的顯示圖片 ?
? ? ? ? } ?
? ? ? ? else if( lblsState == IN_PROCESS ) ?
? ? ? ? { ?
? ? ? ? ? ? setLblsInMask(flags, Point(x,y), false); ?
? ? ? ? ? ? showImage(); ?
? ? ? ? } ?
? ? ? ? else if( prLblsState == IN_PROCESS ) ?
? ? ? ? { ?
? ? ? ? ? ? setLblsInMask(flags, Point(x,y), true); ?
? ? ? ? ? ? showImage(); ?
? ? ? ? } ?
? ? ? ? break; ?
? ? } ?
} ?
??
/*該函數(shù)進(jìn)行g(shù)rabcut算法,并且返回算法運行迭代的次數(shù)*/ ?
int GCApplication::nextIter() ?
{ ?
? ? if( isInitialized ) ?
? ? ? ? //使用grab算法進(jìn)行一次迭代,參數(shù)2為mask,里面存的mask位是:矩形內(nèi)部除掉那些可能是背景或者已經(jīng)確定是背景后的所有的點,且mask同時也為輸出 ?
? ? ? ? //保存的是分割后的前景圖像 ?
? ? ? ? grabCut( *image, mask, rect, bgdModel, fgdModel, 1 ); ?
? ? else ?
? ? { ?
? ? ? ? if( rectState != SET ) ?
? ? ? ? ? ? return iterCount; ?
??
? ? ? ? if( lblsState == SET || prLblsState == SET ) ?
? ? ? ? ? ? grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK ); ?
? ? ? ? else ?
? ? ? ? ? ? grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT ); ?
??
? ? ? ? isInitialized = true; ?
? ? } ?
? ? iterCount++; ?
??
? ? bgdPxls.clear(); fgdPxls.clear(); ?
? ? prBgdPxls.clear(); prFgdPxls.clear(); ?
??
? ? return iterCount; ?
} ?
??
GCApplication gcapp; ?
??
static void on_mouse( int event, int x, int y, int flags, void* param ) ?
{ ?
? ? gcapp.mouseClick( event, x, y, flags, param ); ?
} ?
??
int main( int argc, char** argv ) ?
{ ?
? ? string filename; ?
? ? cout<<" Grabcuts ! \n"; ?
? ? cout<<"input image name: ?"<<endl; ?
? ? cin>>filename; ?
??
? ? ??
? ? Mat image = imread( filename, 1 ); ?
? ? if( image.empty() ) ?
? ? { ?
? ? ? ? cout << "\n Durn, couldn't read image filename " << filename << endl; ?
? ? ? ? return 1; ?
? ? } ?
??
? ? help(); ?
??
? ? const string winName = "image"; ?
? ? cvNamedWindow( winName.c_str(), CV_WINDOW_AUTOSIZE ); ?
? ? cvSetMouseCallback( winName.c_str(), on_mouse, 0 ); ?
??
? ? gcapp.setImageAndWinName( image, winName ); ?
? ? gcapp.showImage(); ?
??
? ? for(;;) ?
? ? { ?
? ? ? ? int c = cvWaitKey(0); ?
? ? ? ? switch( (char) c ) ?
? ? ? ? { ?
? ? ? ? case '\x1b': ?
? ? ? ? ? ? cout << "Exiting ..." << endl; ?
? ? ? ? ? ? goto exit_main; ?
? ? ? ? case 'r': ?
? ? ? ? ? ? cout << endl; ?
? ? ? ? ? ? gcapp.reset(); ?
? ? ? ? ? ? gcapp.showImage(); ?
? ? ? ? ? ? break; ?
? ? ? ? case 'n': ?
? ? ? ? ? ? ComputeTime ct ; ?
? ? ? ? ? ? ct.Begin(); ?
? ? ? ? ? ? ??
? ? ? ? ? ? int iterCount = gcapp.getIterCount(); ?
? ? ? ? ? ? cout << "<" << iterCount << "... "; ?
? ? ? ? ? ? int newIterCount = gcapp.nextIter(); ?
? ? ? ? ? ? if( newIterCount > iterCount ) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? gcapp.showImage(); ?
? ? ? ? ? ? ? ? cout << iterCount << ">" << endl; ?
? ? ? ? ? ? ? ? cout<<"運行時間: ?"<<ct.End()<<endl; ?
? ? ? ? ? ? } ?
? ? ? ? ? ? else ?
? ? ? ? ? ? ? ? cout << "rect must be determined>" << endl; ?
? ? ? ? ? ? break; ?
? ? ? ? } ?
? ? } ?
??
exit_main: ?
? ? cvDestroyWindow( winName.c_str() ); ?
? ? return 0; ?
} ?


?lazy snapping代碼實現(xiàn):
?
// LazySnapping.cpp : 定義控制臺應(yīng)用程序的入口點。 ?
// ?
/* author: zhijie Lee?
?* home page: lzhj.me?
?* 2012-02-06?
?*/ ?
#include "stdafx.h" ?
#include <cv.h> ?
#include <highgui.h> ?
#include "graph.h" ?
#include <vector> ?
#include <iostream> ?
#include <cmath> ?
#include <string> ?
??
using namespace std; ?
??
typedef Graph<float,float,float> GraphType; ?
??
class LasySnapping ?
{ ?
? ? ??
public : ?
? ? LasySnapping(); ?
??
? ? ~LasySnapping() ?
? ? { ??
? ? ? ? if(graph) ?
? ? ? ? { ?
? ? ? ? ? ? delete graph; ?
? ? ? ? } ?
? ? }; ?
private : ?
? ? vector<CvPoint> forePts; ?
? ? vector<CvPoint> backPts; ?
? ? IplImage* image; ?
? ? // average color of foreground points ?
? ? unsigned char avgForeColor[3]; ?
? ? // average color of background points ?
? ? unsigned char avgBackColor[3]; ?
public : ?
? ? void setImage(IplImage* image) ?
? ? { ?
? ? ? ? this->image = image; ?
? ? ? ? graph = new GraphType(image->width*image->height,image->width*image->height*2); ?
? ? } ?
? ? // include-pen locus ?
? ? void setForegroundPoints(vector<CvPoint> pts) ?
? ? { ?
? ? ? ? forePts.clear(); ?
? ? ? ? for(int i =0; i< pts.size(); i++) ?
? ? ? ? { ?
? ? ? ? ? ? if(!isPtInVector(pts[i],forePts)) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? forePts.push_back(pts[i]); ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? ? ? if(forePts.size() == 0) ?
? ? ? ? { ?
? ? ? ? ? ? return; ?
? ? ? ? } ?
? ? ? ? int sum[3] = {0}; ?
? ? ? ? for(int i =0; i < forePts.size(); i++) ?
? ? ? ? { ?
? ? ? ? ? ? unsigned char* p = (unsigned char*)image->imageData + forePts[i].x * 3 ??
? ? ? ? ? ? ? ? + forePts[i].y*image->widthStep; ?
? ? ? ? ? ? sum[0] += p[0]; ?
? ? ? ? ? ? sum[1] += p[1]; ?
? ? ? ? ? ? sum[2] += p[2]; ? ? ? ? ? ? ?
? ? ? ? } ?
? ? ? ? cout<<sum[0]<<" " <<forePts.size()<<endl; ?
? ? ? ? avgForeColor[0] = sum[0]/forePts.size(); ?
? ? ? ? avgForeColor[1] = sum[1]/forePts.size(); ?
? ? ? ? avgForeColor[2] = sum[2]/forePts.size(); ?
? ? } ?
? ? // exclude-pen locus ?
? ? void setBackgroundPoints(vector<CvPoint> pts) ?
? ? { ?
? ? ? ? backPts.clear(); ?
? ? ? ? for(int i =0; i< pts.size(); i++) ?
? ? ? ? { ?
? ? ? ? ? ? if(!isPtInVector(pts[i],backPts)) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? backPts.push_back(pts[i]); ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? ? ? if(backPts.size() == 0) ?
? ? ? ? { ?
? ? ? ? ? ? return; ?
? ? ? ? } ?
? ? ? ? int sum[3] = {0}; ?
? ? ? ? for(int i =0; i < backPts.size(); i++) ?
? ? ? ? { ?
? ? ? ? ? ? unsigned char* p = (unsigned char*)image->imageData + backPts[i].x * 3 + ??
? ? ? ? ? ? ? ? backPts[i].y*image->widthStep; ?
? ? ? ? ? ? sum[0] += p[0]; ?
? ? ? ? ? ? sum[1] += p[1]; ?
? ? ? ? ? ? sum[2] += p[2]; ? ? ? ? ? ? ?
? ? ? ? } ?
? ? ? ? avgBackColor[0] = sum[0]/backPts.size(); ?
? ? ? ? avgBackColor[1] = sum[1]/backPts.size(); ?
? ? ? ? avgBackColor[2] = sum[2]/backPts.size(); ?
? ? } ?
??
? ? // return maxflow of graph ?
? ? int runMaxflow(); ?
? ? // get result, a grayscale mast image indicating forground by 255 and background by 0 ?
? ? IplImage* getImageMask(); ?
??
private : ?
??
? ? float colorDistance(unsigned char* color1, unsigned char* color2); ?
? ? float minDistance(unsigned char* color, vector<CvPoint> points); ?
? ? bool isPtInVector(CvPoint pt, vector<CvPoint> points); ?
? ? void getE1(unsigned char* color,float* energy); ?
? ? float getE2(unsigned char* color1,unsigned char* color2); ?
? ? ??
? ? GraphType *graph; ? ? ?
}; ?
??
LasySnapping::LasySnapping() ?
{ ?
? ? graph = NULL; ?
? ? avgForeColor[0] = 0; ?
? ? avgForeColor[1] = 0; ?
? ? avgForeColor[2] = 0; ?
??
? ? avgBackColor[0] = 0; ?
? ? avgBackColor[1] = 0; ?
? ? avgBackColor[2] = 0; ?
??
? ? ??
} ?
?
float LasySnapping::colorDistance(unsigned char* color1, unsigned char* color2) ?
{ ?
? ? ??
? ? return sqrt(((float)color1[0]-(float)color2[0])*((float)color1[0]-(float)color2[0])+ ?
? ? ? ? ((float)color1[1]-(float)color2[1])*((float)color1[1]-(float)color2[1])+ ?
? ? ? ? ((float)color1[2]-(float)color2[2])*((float)color1[2]-(float)color2[2])); ? ? ?
} ?
??
float LasySnapping::minDistance(unsigned char* color, vector<CvPoint> points) ?
{ ?
? ? float distance = -1; ?
? ? for(int i =0 ; i < points.size(); i++) ?
? ? { ?
? ? ? ? unsigned char* p = (unsigned char*)image->imageData + points[i].y * image->widthStep + ??
? ? ? ? ? ? points[i].x * image->nChannels; ?
? ? ? ? float d = colorDistance(p,color); ?
? ? ? ? if(distance < 0 ) ?
? ? ? ? { ?
? ? ? ? ? ? distance = d; ?
? ? ? ? } ?
? ? ? ? else ?
? ? ? ? { ?
? ? ? ? ? ? if(distance > d) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? distance = d; ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? } ?
??
? ? return distance; ?
} ?
??
bool LasySnapping::isPtInVector(CvPoint pt, vector<CvPoint> points) ?
{ ?
? ? for(int i =0 ; i < points.size(); i++) ?
? ? { ?
? ? ? ? if(pt.x == points[i].x && pt.y == points[i].y) ?
? ? ? ? { ?
? ? ? ? ? ? return true; ?
? ? ? ? } ?
? ? } ?
? ? return false; ?
} ?
void LasySnapping::getE1(unsigned char* color,float* energy) ?
{ ?
? ? // average distance ?
? ? float df = colorDistance(color,avgForeColor); ?
? ? float db = colorDistance(color,avgBackColor); ?
? ? // min distance from background points and forground points ?
? ? // float df = minDistance(color,forePts); ?
? ? // float db = minDistance(color,backPts); ?
? ? energy[0] = df/(db+df); ?
? ? energy[1] = db/(db+df); ?
} ?
??
float LasySnapping::getE2(unsigned char* color1,unsigned char* color2) ?
{ ?
? ? const float EPSILON = 0.01; ?
? ? float lambda = 100; ?
? ? return lambda/(EPSILON+ ?
? ? ? ? (color1[0]-color2[0])*(color1[0]-color2[0])+ ?
? ? ? ? (color1[1]-color2[1])*(color1[1]-color2[1])+ ?
? ? ? ? (color1[2]-color2[2])*(color1[2]-color2[2])); ?
} ?
??
int LasySnapping::runMaxflow() ?
{ ? ??
? ? const float INFINNITE_MAX = 1e10; ?
? ? int indexPt = 0; ?
? ? for(int h = 0; h < image->height; h ++) ?
? ? { ?
? ? ? ? unsigned char* p = (unsigned char*)image->imageData + h *image->widthStep; ?
? ? ? ? for(int w = 0; w < image->width; w ++) ?
? ? ? ? { ?
? ? ? ? ? ? // calculate energe E1 ?
? ? ? ? ? ? float e1[2]={0}; ?
? ? ? ? ? ? if(isPtInVector(cvPoint(w,h),forePts)) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? e1[0] =0; ?
? ? ? ? ? ? ? ? e1[1] = INFINNITE_MAX; ?
? ? ? ? ? ? } ?
? ? ? ? ? ? else if ?
? ? ? ? ? ? ? ? (isPtInVector(cvPoint(w,h),backPts)) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? e1[0] = INFINNITE_MAX; ?
? ? ? ? ? ? ? ? e1[1] = 0; ?
? ? ? ? ? ? } ?
? ? ? ? ? ? else ??
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? getE1(p,e1); ?
? ? ? ? ? ? } ?
??
? ? ? ? ? ? // add node ?
? ? ? ? ? ? graph->add_node(); ?
? ? ? ? ? ? graph->add_tweights(indexPt, e1[0],e1[1]); ?
??
? ? ? ? ? ? // add edge, 4-connect ?
? ? ? ? ? ? if(h > 0 && w > 0) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? float e2 = getE2(p,p-3); ?
? ? ? ? ? ? ? ? graph->add_edge(indexPt,indexPt-1,e2,e2); ?
? ? ? ? ? ? ? ? e2 = getE2(p,p-image->widthStep); ?
? ? ? ? ? ? ? ? graph->add_edge(indexPt,indexPt-image->width,e2,e2); ?
? ? ? ? ? ? } ?
? ? ? ? ? ? ??
? ? ? ? ? ? p+= 3; ?
? ? ? ? ? ? indexPt ++; ? ? ? ? ? ? ?
? ? ? ? } ?
? ? } ?
? ? ??
? ? return graph->maxflow(); ?
} ?
??
IplImage* LasySnapping::getImageMask() ?
{ ?
? ? IplImage* gray = cvCreateImage(cvGetSize(image),8,1); ??
? ? int indexPt =0; ?
? ? for(int h =0; h < image->height; h++) ?
? ? { ?
? ? ? ? unsigned char* p = (unsigned char*)gray->imageData + h*gray->widthStep; ?
? ? ? ? for(int w =0 ;w <image->width; w++) ?
? ? ? ? { ?
? ? ? ? ? ? if (graph->what_segment(indexPt) == GraphType::SOURCE) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? *p = 0; ?
? ? ? ? ? ? } ?
? ? ? ? ? ? else ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? *p = 255; ?
? ? ? ? ? ? } ?
??
? ? ? ? ? ? p++; ?
? ? ? ? ? ? indexPt ++; ?
? ? ? ? } ?
? ? } ?
? ? return gray; ?
} ?
??
// global ?
vector<CvPoint> forePts; ?
vector<CvPoint> backPts; ?
int currentMode = 0;// indicate foreground or background, foreground as default ?
CvScalar paintColor[2] = {CV_RGB(0,0,255),CV_RGB(255,0,0)}; ?
??
IplImage* image = NULL; ?
char* winName = "lazySnapping"; ?
IplImage* imageDraw = NULL; ?
const int SCALE = 4; ?
??
void on_mouse( int event, int x, int y, int flags, void* ) ?
{ ? ? ?
? ? if( event == CV_EVENT_LBUTTONUP ) ?
? ? { ?
? ? ? ? if(backPts.size() == 0 && forePts.size() == 0) ?
? ? ? ? { ?
? ? ? ? ? ? return; ?
? ? ? ? } ?
? ? ? ? LasySnapping ls; ?
? ? ? ? IplImage* imageLS = cvCreateImage(cvSize(image->width/SCALE,image->height/SCALE), ?
? ? ? ? ? ? 8,3); ?
? ? ? ? cvResize(image,imageLS); ?
? ? ? ? ls.setImage(imageLS); ?
? ? ? ? ls.setBackgroundPoints(backPts); ?
? ? ? ? ls.setForegroundPoints(forePts); ?
? ? ? ? ls.runMaxflow(); ?
? ? ? ? IplImage* mask = ls.getImageMask(); ?
? ? ? ? IplImage* gray = cvCreateImage(cvGetSize(image),8,1); ?
? ? ? ? cvResize(mask,gray); ?
? ? ? ? // edge ?
? ? ? ? cvCanny(gray,gray,50,150,3); ?
? ? ? ? ??
? ? ? ? IplImage* showImg = cvCloneImage(imageDraw); ?
? ? ? ? for(int h =0; h < image->height; h ++) ?
? ? ? ? { ?
? ? ? ? ? ? unsigned char* pgray = (unsigned char*)gray->imageData + gray->widthStep*h; ?
? ? ? ? ? ? unsigned char* pimage = (unsigned char*)showImg->imageData + showImg->widthStep*h; ?
? ? ? ? ? ? for(int width ?=0; width < image->width; width++) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? if(*pgray++ != 0 ) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? pimage[0] = 0; ?
? ? ? ? ? ? ? ? ? ? pimage[1] = 255; ?
? ? ? ? ? ? ? ? ? ? pimage[2] = 0; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? pimage+=3; ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? ? ? cvSaveImage("t.bmp",showImg); ?
? ? ? ? cvShowImage(winName,showImg); ?
? ? ? ? cvReleaseImage(&imageLS); ?
? ? ? ? cvReleaseImage(&mask); ?
? ? ? ? cvReleaseImage(&showImg); ?
? ? ? ? cvReleaseImage(&gray); ?
? ? } ?
? ? else if( event == CV_EVENT_LBUTTONDOWN ) ?
? ? { ?
??
? ? } ?
? ? else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON)) ?
? ? { ?
? ? ? ? CvPoint pt = cvPoint(x,y); ?
? ? ? ? if(currentMode == 0) ?
? ? ? ? {//foreground ?
? ? ? ? ? ? forePts.push_back(cvPoint(x/SCALE,y/SCALE)); ?
? ? ? ? } ?
? ? ? ? else ?
? ? ? ? {//background ?
? ? ? ? ? ? backPts.push_back(cvPoint(x/SCALE,y/SCALE)); ?
? ? ? ? } ?
? ? ? ? cvCircle(imageDraw,pt,2,paintColor[currentMode]); ?
? ? ? ? cvShowImage(winName,imageDraw); ?
? ? } ?
} ?
int main(int argc, char** argv) ?
{ ? ??
? ? //if(argc != 2) ?
? ? //{ ?
? ? ?// ? cout<<"command : lazysnapping inputImage"<<endl; ?
? ? ?// ? return 0; ?
? ?// } ?
??
? ? string image_name; ?
? ? cout<<"input image name: "<<endl; ?
? ? cin>>image_name; ?
??
? ? cvNamedWindow(winName,1); ?
? ? cvSetMouseCallback( winName, on_mouse, 0); ?
? ? ??
? ? image = cvLoadImage(image_name.c_str(),CV_LOAD_IMAGE_COLOR); ?
? ? imageDraw = cvCloneImage(image); ?
? ? cvShowImage(winName, image); ?
? ? for(;;) ?
? ? { ?
? ? ? ? int c = cvWaitKey(0); ?
? ? ? ? c = (char)c; ?
? ? ? ? if(c == 27) ?
? ? ? ? {//exit ?
? ? ? ? ? ? break; ?
? ? ? ? } ?
? ? ? ? else if(c == 'r') ?
? ? ? ? {//reset ?
? ? ? ? ? ? image = cvLoadImage(image_name.c_str(),CV_LOAD_IMAGE_COLOR); ?
? ? ? ? ? ? imageDraw = cvCloneImage(image); ?
? ? ? ? ? ? forePts.clear(); ?
? ? ? ? ? ? backPts.clear(); ?
? ? ? ? ? ? currentMode = 0; ?
? ? ? ? ? ? cvShowImage(winName, image); ?
? ? ? ? } ?
? ? ? ? else if(c == 'b') ?
? ? ? ? {//change to background selection ?
? ? ? ? ? ? currentMode = 1; ?
? ? ? ? }else if(c == 'f') ?
? ? ? ? {//change to foreground selection ?
? ? ? ? ? ? currentMode = 0; ?
? ? ? ? } ?
? ? } ?
? ? cvReleaseImage(&image); ?
? ? cvReleaseImage(&imageDraw); ?
? ? return 0; ?
} ?


?
=======

?OpenCV由漢字生成圖片(透明)



? ? ? ? 今天聽說很多同志們寫畢業(yè)論文重復(fù)率過高的問題,大牛說用圖片代替字就行了,我就想用OpenCV實現(xiàn)一下看看能不能搞,果不其然還是可以的!!!主要的難點在于普通格式的圖片背景不透明,需要使用背景透明的png格式圖片就行。
?
主要思想和步驟:
?
1.首先配置好FreeType與OpenCV,添加編譯好的lib,與include目錄和CvxText.h和CvxText.cpp就行了,參考[1]
?
2.說一下思路,主要就是OpenCV版本的問題造成有的函數(shù)用的IplImage,而函數(shù)
//設(shè)置原圖像文字
?text.putText(ImageSrc, msg, cvPoint(1, size_zi), color);
只能接受IplImage格式的參數(shù),所以保存成png,就比較麻煩了。
?
png格式的圖片是4個通道,按照BGRA來放置,alaph就是透明通道。我們的思路就是按照原來直接給圖片上疊加文字的辦法,新建與文字大小相同的圖片,然后二值化,按照二值模版生成新的png文字圖片,有字的地方添上顏色,沒字的地方設(shè)置為透明。
?
當(dāng)然二值化算法網(wǎng)上搜了一個自適應(yīng)閥值的算法效果非常好
?
?
3.生成了透明的文字圖片,粘貼到論文里面,估計查詢重復(fù)的系統(tǒng)再牛逼也是無能為力了。后序有空做一些程序界面跟字符分割的東西,可以直接賣錢了。
當(dāng)然,字體跟大小,上下邊距都是可以設(shè)置的,后序再往程序里面寫。
?
?
實現(xiàn)效果:
?
?
主要代碼:


// AddChinese.cpp : 定義控制臺應(yīng)用程序的入口點。 ?
// ?
??
#include "stdafx.h" ?
??
??
??
#include <opencv2/core/core.hpp> ? ?
#include <opencv2/highgui/highgui.hpp> ?
#include "CvxText.h" ?
??
#pragma comment(lib,"freetype255d.lib") ?
#pragma comment(lib,"opencv_core2410d.lib") ? ? ? ? ? ? ? ? ?
#pragma comment(lib,"opencv_highgui2410d.lib") ? ? ? ? ? ? ? ? ?
#pragma comment(lib,"opencv_imgproc2410d.lib") ? ??
??
using namespace std; ?
using namespace cv; ?
??
#define ROW_BLOCK 2 ?
#define COLUMN_Block 2 ?
??
// writePng.cpp : 定義控制臺應(yīng)用程序的入口點。 ?
// ?
??
??
int run_test_png(Mat &mat,string image_name) ?
{ ?
??
??
? ? /*采用自己設(shè)置的參數(shù)來保存圖片*/ ?
? ? //Mat mat(480, 640, CV_8UC4); ?
? ? //createAlphaMat(mat); ?
? ? vector<int> compression_params; ?
? ? compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION); ?
? ? compression_params.push_back(9); ? ?//png格式下,默認(rèn)的參數(shù)為3. ?
? ? try ??
? ? { ?
? ? ? ? imwrite(image_name, mat, compression_params); ?
? ? } ?
? ? catch (runtime_error& ex) ??
? ? { ?
? ? ? ? fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what()); ?
? ? ? ? return 1; ?
? ? } ?
? ? fprintf(stdout, "Saved PNG file with alpha data.\n"); ?
??
? ? waitKey(0); ?
? ? return 0; ?
} ?
??
int coloured(Mat &template_src, Mat &mat_png, CvScalar color) ?
{ ?
??
? ? for (int i = 0; i < template_src.rows; ++i) ??
? ? { ?
? ? ? ? for (int j = 0; j < template_src.cols; ++j) ??
? ? ? ? { ?
? ? ? ? ? ? Vec4b& bgra = mat_png.at<Vec4b>(i, j); ?
? ? ? ? ? ? //int temp = template_src.at<uchar>(i,j); ?
? ? ? ? ? ? if (template_src.at<uchar>(i,j)== 0) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? bgra[0] = color.val[0]; ? ?//b通道 ?
? ? ? ? ? ? ? ? bgra[1] = color.val[1]; ? ? //g通道 ?
? ? ? ? ? ? ? ? bgra[2] = color.val[2]; ? ? //r通道 ?
? ? ? ? ? ? ? ? bgra[3] = 255;//alpha通道全部設(shè)置為透明完全透明為0,否則為255 ?
? ? ? ? ? ? } ?
? ? ? ? ? ? else ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? bgra[3] = 0;//alpha通道全部設(shè)置為透明完全透明為0,否則為255 ?
? ? ? ? ? ? } ?
? ? ? ? ? ? ??
? ? ? ? ? ? ??
? ? ? ? ? ? ??
? ? ? ? } ?
? ? } ?
??
? ? return 0; ?
} ?
??
void ImageBinarization(IplImage *src) ?
{ ? /*對灰度圖像二值化,自適應(yīng)門限threshold*/ ?
? ? int i,j,width,height,step,chanel,threshold; ?
? ? /*size是圖像尺寸,svg是灰度直方圖均值,va是方差*/ ?
? ? float size,avg,va,maxVa,p,a,s; ?
? ? unsigned char *dataSrc; ?
? ? float histogram[256]; ?
??
? ? width = src->width; ?
? ? height = src->height; ?
? ? dataSrc = (unsigned char *)src->imageData; ?
? ? step = src->widthStep/sizeof(char); ?
? ? chanel = src->nChannels; ?
? ? /*計算直方圖并歸一化histogram*/ ?
? ? for(i=0; i<256; i++) ?
? ? ? ? histogram[i] = 0; ?
? ? for(i=0; i<height; i++) ?
? ? ? ? for(j=0; j<width*chanel; j++) ?
? ? ? ? { ?
? ? ? ? ? ? histogram[dataSrc[i*step+j]-'0'+48]++; ?
? ? ? ? } ?
? ? ? ? size = width * height; ?
? ? ? ? for(i=0; i<256; i++) ?
? ? ? ? ? ? histogram[i] /=size; ?
? ? ? ? /*計算灰度直方圖中值和方差*/ ?
? ? ? ? avg = 0; ?
? ? ? ? for(i=0; i<256; i++) ?
? ? ? ? ? ? avg += i*histogram[i]; ?
? ? ? ? va = 0; ?
? ? ? ? for(i=0; i<256; i++) ?
? ? ? ? ? ? va += fabs(i*i*histogram[i]-avg*avg); ?
? ? ? ? /*利用加權(quán)最大方差求門限*/ ?
? ? ? ? threshold = 20; ?
? ? ? ? maxVa = 0; ?
? ? ? ? p = a = s = 0; ?
? ? ? ? for(i=0; i<256; i++) ?
? ? ? ? { ?
? ? ? ? ? ? p += histogram[i]; ?
? ? ? ? ? ? a += i*histogram[i]; ?
? ? ? ? ? ? s = (avg*p-a)*(avg*p-a)/p/(1-p); ?
? ? ? ? ? ? if(s > maxVa) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? threshold = i; ?
? ? ? ? ? ? ? ? maxVa = s; ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? ? ? /*二值化*/ ?
? ? ? ? for(i=0; i<height; i++) ?
? ? ? ? ? ? for(j=0; j<width*chanel; j++) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? if(dataSrc[i*step+j] > threshold) ?
? ? ? ? ? ? ? ? ? ? dataSrc[i*step+j] = 255; ?
? ? ? ? ? ? ? ? else ?
? ? ? ? ? ? ? ? ? ? dataSrc[i*step+j] = 0; ?
? ? ? ? ? ? } ?
} ?
??
Mat binaryzation(Mat &src) ?
{ ?
? ? Mat des_gray(src.size(),CV_8UC1); ?
??
? ? cvtColor(src,des_gray,CV_BGR2GRAY); ?
? ? ??
? ? //Mat bin_mat(); ?
? ? IplImage temp(des_gray); ?
? ? ImageBinarization(&temp); ?
??
??
? ? //threshold(des_gray,des_gray,150,255,THRESH_BINARY); ?
? ? imshow("二值圖像",des_gray); ?
? ? return des_gray; ?
} ?
??
int generate_chinese(const int size_zi, const char *msg ,int number,CvScalar color) ?
{ ?
? ? //int size_zi = 50;//字體大小 ?
? ? CvSize czSize; ?//目標(biāo)圖像尺寸 ?
? ? float p = 0.5; ?
? ? CvScalar fsize; ?
??
??
? ? //讀取TTF字體文件 ?
? ? CvxText text("simhei.ttf"); ? ? ??
??
? ? //設(shè)置字體屬性 字體大小/空白比例/間隔比例/旋轉(zhuǎn)角度 ?
? ? fsize = cvScalar(size_zi, 1, 0.1, 0); ?
? ? text.setFont(NULL, &fsize, NULL, &p); ? ? ? ?
??
? ? czSize.width = size_zi*number; ?
? ? czSize.height = size_zi; ?
? ? //加載原圖像 ?
? ? IplImage* ImageSrc = cvCreateImage(czSize,IPL_DEPTH_8U,3);//cvLoadImage(Imagename, CV_LOAD_IMAGE_UNCHANGED); ?
? ? //Mat image(ImageSrc); ?
? ? //createAlphaMat(image); ?
? ? //ImageSrc = ? ?
??
? ? //IplImage temp(image); ??
? ? //ImageSrc = &temp; ?
??
? ? //設(shè)置原圖像文字 ?
? ? text.putText(ImageSrc, msg, cvPoint(1, size_zi), color); ??
??
? ? //顯示原圖像 ?
? ? cvShowImage("原圖", ImageSrc); ?
??
??
? ? string hanzi = msg; ?
? ? hanzi = hanzi + ".png"; ?
??
? ? Mat chinese(ImageSrc,true); ?
? ? Mat gray = binaryzation(chinese); ?
??
? ? imwrite("chinese_gray.jpg",gray); ?
??
? ? Mat mat_png(chinese.size(),CV_8UC4); ?
? ? coloured(gray,mat_png,color); ?
? ? run_test_png(mat_png,hanzi); ?
? ? // ?
? ? cvSaveImage("hanzi.jpg",reDstImage); ?
? ? //run_test_png(chinese,hanzi); ?
? ? //等待按鍵事件 ?
? ? cvWaitKey(); ?
? ? return 0; ?
} ?
??
int main() ?
{ ?
? ? CvScalar color = CV_RGB(0,0,0); ?
? ? int size = 200; ?
? ? const char* msg = "你好a";//暫時一行字不要太長 ?
??
? ? int number = 3;//字符個數(shù) ?
??
? ? generate_chinese(size,msg,number,color); ?
? ? ??
??
? ? return 0; ?
} ?


?
完整工程下載:
http://download.csdn.net/detail/wangyaninglm/8486521
?
參考文獻(xiàn):
?
http://blog.csdn.net/fengbingchun/article/details/8029337
http://www.oschina.net/code/snippet_1447359_36028
http://blog.csdn.net/hustspy1990/article/details/6301592
========

總結(jié)

以上是生活随笔為你收集整理的opencv图像处理总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

中文精品无码中文字幕无码专区 | 成人免费视频视频在线观看 免费 | 亚洲综合伊人久久大杳蕉 | а天堂中文在线官网 | 久久亚洲国产成人精品性色 | 麻花豆传媒剧国产免费mv在线 | 少妇邻居内射在线 | www国产亚洲精品久久网站 | 日本大乳高潮视频在线观看 | 日日鲁鲁鲁夜夜爽爽狠狠 | 日韩精品无码免费一区二区三区 | 欧美老人巨大xxxx做受 | 国产极品视觉盛宴 | 丰满人妻翻云覆雨呻吟视频 | 日本在线高清不卡免费播放 | 亚洲欧美日韩国产精品一区二区 | 亚洲 欧美 激情 小说 另类 | 国产高清不卡无码视频 | 男人和女人高潮免费网站 | 老熟女重囗味hdxx69 | 乱人伦中文视频在线观看 | 亚洲精品欧美二区三区中文字幕 | 蜜桃视频插满18在线观看 | 国产激情精品一区二区三区 | 国产在线一区二区三区四区五区 | 欧美人与禽zoz0性伦交 | 国内精品九九久久久精品 | 国产精品办公室沙发 | 无码精品国产va在线观看dvd | 一二三四在线观看免费视频 | 日本欧美一区二区三区乱码 | 精品欧洲av无码一区二区三区 | 欧美大屁股xxxxhd黑色 | 日本大香伊一区二区三区 | 亚洲精品一区二区三区四区五区 | 人妻尝试又大又粗久久 | 成人无码精品一区二区三区 | 国产超级va在线观看视频 | 一本久久伊人热热精品中文字幕 | 免费看男女做好爽好硬视频 | 超碰97人人射妻 | 日韩视频 中文字幕 视频一区 | 日韩在线不卡免费视频一区 | 国产午夜亚洲精品不卡下载 | 久久久久久久女国产乱让韩 | 久久久无码中文字幕久... | 欧美野外疯狂做受xxxx高潮 | 亚洲午夜久久久影院 | 亚洲精品一区国产 | 日本一区二区三区免费高清 | 无码人妻丰满熟妇区毛片18 | аⅴ资源天堂资源库在线 | 久久精品女人的天堂av | 国产亚洲人成在线播放 | 无码人妻久久一区二区三区不卡 | 强伦人妻一区二区三区视频18 | 精品无码一区二区三区的天堂 | 欧美日本免费一区二区三区 | 国产内射爽爽大片视频社区在线 | 欧美35页视频在线观看 | 国产手机在线αⅴ片无码观看 | 少妇无码av无码专区在线观看 | 亚洲欧洲无卡二区视頻 | 女高中生第一次破苞av | 午夜理论片yy44880影院 | 欧美一区二区三区视频在线观看 | 女人被爽到呻吟gif动态图视看 | 日韩人妻无码一区二区三区久久99 | 激情内射亚州一区二区三区爱妻 | 超碰97人人做人人爱少妇 | 精品一区二区三区无码免费视频 | 欧美日本免费一区二区三区 | 精品 日韩 国产 欧美 视频 | 欧美老熟妇乱xxxxx | 99精品视频在线观看免费 | 麻花豆传媒剧国产免费mv在线 | 永久免费观看国产裸体美女 | 东京热男人av天堂 | 欧美丰满老熟妇xxxxx性 | 无码任你躁久久久久久久 | 亚洲国产精华液网站w | 精品人妻人人做人人爽 | 成人无码视频免费播放 | 激情爆乳一区二区三区 | 国产精品香蕉在线观看 | 性做久久久久久久久 | 国产超级va在线观看视频 | 亚洲 日韩 欧美 成人 在线观看 | 蜜桃av蜜臀av色欲av麻 999久久久国产精品消防器材 | 国产成人午夜福利在线播放 | 四十如虎的丰满熟妇啪啪 | 久久五月精品中文字幕 | 性生交大片免费看l | 久久综合九色综合欧美狠狠 | 日日摸天天摸爽爽狠狠97 | 亚洲综合在线一区二区三区 | 久久午夜无码鲁丝片秋霞 | 国产尤物精品视频 | 欧美亚洲日韩国产人成在线播放 | 日日橹狠狠爱欧美视频 | 香蕉久久久久久av成人 | 国产精品爱久久久久久久 | 国语自产偷拍精品视频偷 | 黑人巨大精品欧美黑寡妇 | 午夜丰满少妇性开放视频 | 1000部啪啪未满十八勿入下载 | 亚洲 激情 小说 另类 欧美 | 秋霞成人午夜鲁丝一区二区三区 | 欧美性猛交xxxx富婆 | 伊在人天堂亚洲香蕉精品区 | 熟妇人妻中文av无码 | 亚洲无人区午夜福利码高清完整版 | 精品欧美一区二区三区久久久 | 国产人妻人伦精品1国产丝袜 | 成 人 网 站国产免费观看 | 亚洲成在人网站无码天堂 | 国产亚洲精品久久久ai换 | 久久这里只有精品视频9 | 18禁止看的免费污网站 | 亚洲综合在线一区二区三区 | 日韩精品无码免费一区二区三区 | 九一九色国产 | 在线 国产 欧美 亚洲 天堂 | 亚洲成a人片在线观看无码 | 国产人妻人伦精品 | 波多野结衣一区二区三区av免费 | 一本久道久久综合婷婷五月 | 中文字幕无码免费久久99 | 日产精品高潮呻吟av久久 | 久久www免费人成人片 | 亚洲中文字幕在线无码一区二区 | 欧美成人午夜精品久久久 | 中文字幕乱码亚洲无线三区 | av香港经典三级级 在线 | 日韩欧美中文字幕在线三区 | 午夜无码区在线观看 | 午夜精品一区二区三区在线观看 | 女高中生第一次破苞av | 国产女主播喷水视频在线观看 | 久久久国产一区二区三区 | 色 综合 欧美 亚洲 国产 | 蜜臀av无码人妻精品 | 2020久久超碰国产精品最新 | 欧美成人免费全部网站 | √天堂资源地址中文在线 | 国产精品人人妻人人爽 | 亚洲理论电影在线观看 | 无码国产乱人伦偷精品视频 | 国产成人人人97超碰超爽8 | 国产乱人偷精品人妻a片 | 精品 日韩 国产 欧美 视频 | 欧美日韩久久久精品a片 | 欧洲精品码一区二区三区免费看 | 熟女体下毛毛黑森林 | 丰腴饱满的极品熟妇 | 少妇的肉体aa片免费 | 丰腴饱满的极品熟妇 | 久久久精品国产sm最大网站 | 欧美第一黄网免费网站 | 成年美女黄网站色大免费全看 | 久久久久久av无码免费看大片 | 欧美乱妇无乱码大黄a片 | 理论片87福利理论电影 | 黑人巨大精品欧美一区二区 | 久久www免费人成人片 | 欧美日韩一区二区免费视频 | 久久久久亚洲精品男人的天堂 | 一本无码人妻在中文字幕免费 | 精品一二三区久久aaa片 | 久久国产精品萌白酱免费 | 一区二区三区乱码在线 | 欧洲 | 3d动漫精品啪啪一区二区中 | 天干天干啦夜天干天2017 | 国产精品毛片一区二区 | 狠狠色欧美亚洲狠狠色www | 日本乱偷人妻中文字幕 | 亚洲精品综合一区二区三区在线 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 老子影院午夜精品无码 | 国产做国产爱免费视频 | 欧美zoozzooz性欧美 | 俺去俺来也在线www色官网 | 人人妻人人澡人人爽欧美一区九九 | 精品久久综合1区2区3区激情 | 亚洲精品一区三区三区在线观看 | 人人妻人人藻人人爽欧美一区 | av人摸人人人澡人人超碰下载 | 国产成人综合在线女婷五月99播放 | 无码成人精品区在线观看 | 久久午夜无码鲁丝片秋霞 | 国产人妻人伦精品1国产丝袜 | 人人妻人人澡人人爽欧美一区 | 丰满人妻翻云覆雨呻吟视频 | 久久久精品欧美一区二区免费 | 亚洲gv猛男gv无码男同 | 成人欧美一区二区三区 | 国产一区二区三区日韩精品 | 精品 日韩 国产 欧美 视频 | 久久99精品国产麻豆蜜芽 | 熟妇人妻无乱码中文字幕 | 欧美午夜特黄aaaaaa片 | 永久免费观看国产裸体美女 | 欧美精品免费观看二区 | 成人动漫在线观看 | 久久久成人毛片无码 | 国产黑色丝袜在线播放 | 国产精品视频免费播放 | 粗大的内捧猛烈进出视频 | 国产成人无码一二三区视频 | 亚洲区欧美区综合区自拍区 | 中文字幕 人妻熟女 | 俄罗斯老熟妇色xxxx | 最新国产乱人伦偷精品免费网站 | 日韩无码专区 | 精品乱子伦一区二区三区 | 高潮毛片无遮挡高清免费视频 | 久久久精品人妻久久影视 | 亚洲成av人综合在线观看 | 免费观看又污又黄的网站 | 国产suv精品一区二区五 | 人妻少妇精品久久 | 欧美日韩视频无码一区二区三 | 99久久久无码国产精品免费 | 久青草影院在线观看国产 | 无码人妻丰满熟妇区毛片18 | 国产精品无码久久av | 麻豆精品国产精华精华液好用吗 | 亚拍精品一区二区三区探花 | 国产精品99久久精品爆乳 | 欧美人与善在线com | 国产亚洲欧美日韩亚洲中文色 | 色欲久久久天天天综合网精品 | 亚洲а∨天堂久久精品2021 | 中文字幕人妻丝袜二区 | 青青草原综合久久大伊人精品 | 图片区 小说区 区 亚洲五月 | 亚洲熟妇色xxxxx亚洲 | 人妻天天爽夜夜爽一区二区 | 97夜夜澡人人爽人人喊中国片 | 久久国产劲爆∧v内射 | 超碰97人人做人人爱少妇 | 日本在线高清不卡免费播放 | 精品无码av一区二区三区 | 午夜福利试看120秒体验区 | 少妇被黑人到高潮喷出白浆 | 欧美国产亚洲日韩在线二区 | 色婷婷av一区二区三区之红樱桃 | 中文无码成人免费视频在线观看 | www国产亚洲精品久久久日本 | 中文无码精品a∨在线观看不卡 | 男人扒开女人内裤强吻桶进去 | 成人免费无码大片a毛片 | 国产美女精品一区二区三区 | 久久国语露脸国产精品电影 | 久久亚洲中文字幕精品一区 | 精品日本一区二区三区在线观看 | 欧美丰满老熟妇xxxxx性 | 久久精品女人天堂av免费观看 | 欧美国产日韩久久mv | 国产无av码在线观看 | 黑人粗大猛烈进出高潮视频 | 国产口爆吞精在线视频 | 99久久精品国产一区二区蜜芽 | 人人妻人人澡人人爽欧美一区九九 | 六月丁香婷婷色狠狠久久 | 亚洲日韩中文字幕在线播放 | 清纯唯美经典一区二区 | 亚洲欧美国产精品久久 | 国产免费久久精品国产传媒 | 欧美亚洲国产一区二区三区 | 亚洲午夜无码久久 | 人妻少妇精品无码专区动漫 | 久久久久亚洲精品男人的天堂 | 成人性做爰aaa片免费看 | 国产av一区二区精品久久凹凸 | 日本www一道久久久免费榴莲 | 亚洲精品综合五月久久小说 | 日韩人妻无码一区二区三区久久99 | 97资源共享在线视频 | 久久久精品欧美一区二区免费 | 国产亚洲精品久久久久久国模美 | 亚洲理论电影在线观看 | 久久国产精品萌白酱免费 | 免费国产成人高清在线观看网站 | 欧美变态另类xxxx | 日韩人妻少妇一区二区三区 | av人摸人人人澡人人超碰下载 | 精品水蜜桃久久久久久久 | 全黄性性激高免费视频 | 午夜免费福利小电影 | 久精品国产欧美亚洲色aⅴ大片 | 国产精品va在线播放 | 国产精品自产拍在线观看 | 色欲久久久天天天综合网精品 | 无码精品国产va在线观看dvd | 少妇性l交大片 | 国产极品美女高潮无套在线观看 | 午夜福利试看120秒体验区 | 欧美熟妇另类久久久久久多毛 | 精品国产福利一区二区 | 精品国偷自产在线 | 一本无码人妻在中文字幕免费 | 18禁止看的免费污网站 | 麻豆国产97在线 | 欧洲 | 国产成人无码一二三区视频 | 中文字幕无码人妻少妇免费 | a在线观看免费网站大全 | 国内精品久久毛片一区二区 | 欧美 日韩 亚洲 在线 | 日本护士毛茸茸高潮 | 国产午夜精品一区二区三区嫩草 | 学生妹亚洲一区二区 | 国产精品亚洲lv粉色 | 荫蒂添的好舒服视频囗交 | 欧洲欧美人成视频在线 | 中文字幕乱码中文乱码51精品 | 牛和人交xxxx欧美 | 99久久精品无码一区二区毛片 | 亚洲啪av永久无码精品放毛片 | 国产亚洲精品久久久久久久久动漫 | 久久精品人人做人人综合试看 | 国产97色在线 | 免 | 国产免费久久久久久无码 | 亚洲成av人在线观看网址 | 亚洲综合伊人久久大杳蕉 | 波多野结衣一区二区三区av免费 | 国产办公室秘书无码精品99 | 色偷偷人人澡人人爽人人模 | 欧洲欧美人成视频在线 | 国产超碰人人爽人人做人人添 | 亚洲综合在线一区二区三区 | 亚洲日韩一区二区三区 | 欧美 日韩 亚洲 在线 | 中文字幕亚洲情99在线 | 国产精品多人p群无码 | 日韩 欧美 动漫 国产 制服 | 精品欧美一区二区三区久久久 | 亚洲国产午夜精品理论片 | 人妻无码久久精品人妻 | 国产免费久久精品国产传媒 | 性欧美熟妇videofreesex | 亚洲成a人片在线观看日本 | 好屌草这里只有精品 | 久久99热只有频精品8 | 日韩亚洲欧美精品综合 | 小sao货水好多真紧h无码视频 | 丰满诱人的人妻3 | 青青草原综合久久大伊人精品 | 色老头在线一区二区三区 | aⅴ亚洲 日韩 色 图网站 播放 | 亚洲中文无码av永久不收费 | 在线欧美精品一区二区三区 | 国产亚洲精品久久久ai换 | 亚洲精品久久久久久一区二区 | 中文字幕无码日韩欧毛 | 国产亚洲精品久久久久久久 | 蜜桃臀无码内射一区二区三区 | 亚洲国产精品久久人人爱 | 67194成是人免费无码 | 高潮毛片无遮挡高清免费 | 久久国产36精品色熟妇 | 国产精品理论片在线观看 | 天下第一社区视频www日本 | 国产热a欧美热a在线视频 | 中文字幕日韩精品一区二区三区 | 男女作爱免费网站 | 国产精品多人p群无码 | 国内揄拍国内精品人妻 | 啦啦啦www在线观看免费视频 | 最近中文2019字幕第二页 | 国产另类ts人妖一区二区 | 国产手机在线αⅴ片无码观看 | 亚欧洲精品在线视频免费观看 | 高清无码午夜福利视频 | 久久国产精品二国产精品 | 久久人人爽人人爽人人片ⅴ | 人妻少妇精品久久 | 精品无码国产自产拍在线观看蜜 | 国产精品高潮呻吟av久久 | 久久天天躁狠狠躁夜夜免费观看 | 亚洲第一无码av无码专区 | 国产熟妇高潮叫床视频播放 | 亚洲伊人久久精品影院 | 国产深夜福利视频在线 | 乱码av麻豆丝袜熟女系列 | 婷婷丁香五月天综合东京热 | 国产成人无码区免费内射一片色欲 | 宝宝好涨水快流出来免费视频 | 老子影院午夜伦不卡 | 日韩av无码中文无码电影 | 国产香蕉尹人视频在线 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 成人精品视频一区二区三区尤物 | 亚洲天堂2017无码 | 亚洲熟女一区二区三区 | 波多野42部无码喷潮在线 | 荫蒂被男人添的好舒服爽免费视频 | 亚洲码国产精品高潮在线 | 在线播放亚洲第一字幕 | 国产精品无码永久免费888 | 久久 国产 尿 小便 嘘嘘 | 精品午夜福利在线观看 | 99久久精品国产一区二区蜜芽 | 真人与拘做受免费视频 | 激情爆乳一区二区三区 | 粉嫩少妇内射浓精videos | 国产精品自产拍在线观看 | 成人动漫在线观看 | 亚洲午夜久久久影院 | 国产精品-区区久久久狼 | 131美女爱做视频 | 粉嫩少妇内射浓精videos | 久久久精品国产sm最大网站 | 老太婆性杂交欧美肥老太 | 国产亲子乱弄免费视频 | 久久精品中文字幕大胸 | 婷婷五月综合缴情在线视频 | 精品人妻中文字幕有码在线 | 国产人妻精品一区二区三区 | 无遮无挡爽爽免费视频 | 中文字幕无码热在线视频 | 波多野结衣av一区二区全免费观看 | 疯狂三人交性欧美 | 亚洲中文字幕在线观看 | 少妇太爽了在线观看 | 中文字幕 人妻熟女 | 国产精品无码久久av | 国内综合精品午夜久久资源 | 香港三级日本三级妇三级 | 少女韩国电视剧在线观看完整 | 亚洲色欲色欲欲www在线 | 色五月五月丁香亚洲综合网 | 呦交小u女精品视频 | 捆绑白丝粉色jk震动捧喷白浆 | 无码一区二区三区在线 | 欧美阿v高清资源不卡在线播放 | 亚洲午夜福利在线观看 | 无码精品国产va在线观看dvd | 国色天香社区在线视频 | 国产亚av手机在线观看 | 十八禁视频网站在线观看 | 熟妇女人妻丰满少妇中文字幕 | 麻豆精品国产精华精华液好用吗 | 无码毛片视频一区二区本码 | 免费中文字幕日韩欧美 | 波多野结衣av在线观看 | 麻豆精产国品 | 又大又紧又粉嫩18p少妇 | 久久久久免费看成人影片 | 图片区 小说区 区 亚洲五月 | 午夜精品久久久内射近拍高清 | 亚洲中文字幕成人无码 | 一个人看的www免费视频在线观看 | 初尝人妻少妇中文字幕 | 国产午夜亚洲精品不卡下载 | 亚洲日韩av一区二区三区四区 | 亚洲综合精品香蕉久久网 | 亚洲中文字幕无码一久久区 | 久久国产精品偷任你爽任你 | 亚洲 欧美 激情 小说 另类 | 久久精品无码一区二区三区 | 51国偷自产一区二区三区 | 中文字幕日韩精品一区二区三区 | 最新版天堂资源中文官网 | 亚洲成色在线综合网站 | 水蜜桃亚洲一二三四在线 | 国产精品毛多多水多 | 狠狠色色综合网站 | 在线 国产 欧美 亚洲 天堂 | 欧美日韩一区二区免费视频 | 老头边吃奶边弄进去呻吟 | 午夜福利一区二区三区在线观看 | 少妇性l交大片 | 国产精品高潮呻吟av久久4虎 | 东京热一精品无码av | 国产一区二区三区精品视频 | 中文字幕无码视频专区 | 成人免费视频视频在线观看 免费 | 国产人成高清在线视频99最全资源 | 国产综合在线观看 | 亚洲一区二区三区在线观看网站 | 欧美精品国产综合久久 | 亚洲精品一区国产 | 国产高清av在线播放 | 国产一区二区三区四区五区加勒比 | 亚洲gv猛男gv无码男同 | 亚洲国产成人av在线观看 | 色偷偷人人澡人人爽人人模 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 色窝窝无码一区二区三区色欲 | 装睡被陌生人摸出水好爽 | 久久99国产综合精品 | 兔费看少妇性l交大片免费 | 国产熟妇另类久久久久 | 亚洲熟妇自偷自拍另类 | www成人国产高清内射 | 蜜臀av在线播放 久久综合激激的五月天 | 色一情一乱一伦一区二区三欧美 | 国产国产精品人在线视 | 99久久久无码国产精品免费 | 亚洲呦女专区 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 午夜理论片yy44880影院 | 欧美xxxxx精品 | 精品久久综合1区2区3区激情 | 亚洲人亚洲人成电影网站色 | 精品一区二区三区波多野结衣 | 久久久精品欧美一区二区免费 | 中文字幕无码免费久久9一区9 | 澳门永久av免费网站 | 国产免费久久久久久无码 | 99精品无人区乱码1区2区3区 | 国产精品高潮呻吟av久久 | 久久久www成人免费毛片 | 成人欧美一区二区三区 | 国产sm调教视频在线观看 | 久久精品国产99精品亚洲 | 97无码免费人妻超级碰碰夜夜 | 久久精品国产精品国产精品污 | 日韩欧美中文字幕公布 | 色老头在线一区二区三区 | 中文字幕无码视频专区 | 国产免费观看黄av片 | 国产成人无码av片在线观看不卡 | 欧美日韩人成综合在线播放 | 久9re热视频这里只有精品 | √天堂资源地址中文在线 | а√天堂www在线天堂小说 | 女人和拘做爰正片视频 | 日本熟妇浓毛 | 国产激情无码一区二区app | 久久久av男人的天堂 | 曰韩无码二三区中文字幕 | 乱人伦中文视频在线观看 | 日本在线高清不卡免费播放 | 国产真人无遮挡作爱免费视频 | 麻豆国产丝袜白领秘书在线观看 | 欧美人与动性行为视频 | 国产一区二区三区影院 | 精品无码国产自产拍在线观看蜜 | 亚洲色大成网站www | 免费看男女做好爽好硬视频 | 欧美老妇交乱视频在线观看 | 免费乱码人妻系列无码专区 | 亚洲中文字幕在线观看 | 国产99久久精品一区二区 | 天海翼激烈高潮到腰振不止 | 亚洲国产av精品一区二区蜜芽 | 午夜成人1000部免费视频 | 大肉大捧一进一出视频出来呀 | 亚洲综合伊人久久大杳蕉 | 国产乱码精品一品二品 | 欧美熟妇另类久久久久久不卡 | 国产三级久久久精品麻豆三级 | 在线观看欧美一区二区三区 | 精品无人区无码乱码毛片国产 | 久久久久免费精品国产 | 老熟妇仑乱视频一区二区 | 免费人成在线视频无码 | √8天堂资源地址中文在线 | 波多野结衣一区二区三区av免费 | 99精品视频在线观看免费 | 鲁鲁鲁爽爽爽在线视频观看 | 中文字幕日产无线码一区 | 日本va欧美va欧美va精品 | 日本大乳高潮视频在线观看 | 麻豆成人精品国产免费 | 久久精品国产亚洲精品 | 成年美女黄网站色大免费视频 | 日韩精品乱码av一区二区 | 中文字幕色婷婷在线视频 | 国产婷婷色一区二区三区在线 | 大地资源中文第3页 | 国精产品一品二品国精品69xx | 曰本女人与公拘交酡免费视频 | 无人区乱码一区二区三区 | 色老头在线一区二区三区 | 欧美自拍另类欧美综合图片区 | 漂亮人妻洗澡被公强 日日躁 | 97精品人妻一区二区三区香蕉 | 久久午夜夜伦鲁鲁片无码免费 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国产超级va在线观看视频 | 精品水蜜桃久久久久久久 | 无码人妻出轨黑人中文字幕 | 久久久久人妻一区精品色欧美 | 国产一区二区三区日韩精品 | 国产莉萝无码av在线播放 | 青青久在线视频免费观看 | 少妇高潮一区二区三区99 | 天堂亚洲2017在线观看 | 永久免费精品精品永久-夜色 | 亚洲自偷精品视频自拍 | 一区二区传媒有限公司 | 国产激情一区二区三区 | 亚洲va欧美va天堂v国产综合 | 国产精品美女久久久 | 美女毛片一区二区三区四区 | 四虎国产精品一区二区 | 婷婷五月综合激情中文字幕 | 久久久久久久人妻无码中文字幕爆 | 国产精品内射视频免费 | 精品国产青草久久久久福利 | 最近的中文字幕在线看视频 | 国产高清av在线播放 | 野狼第一精品社区 | 亚洲人成网站在线播放942 | 中文字幕 人妻熟女 | 扒开双腿疯狂进出爽爽爽视频 | 国产亚av手机在线观看 | 久久综合激激的五月天 | 色婷婷香蕉在线一区二区 | 日欧一片内射va在线影院 | 欧美高清在线精品一区 | 国产色视频一区二区三区 | 亚洲综合另类小说色区 | 久久亚洲日韩精品一区二区三区 | 免费国产黄网站在线观看 | 免费人成在线视频无码 | 国产69精品久久久久app下载 | 久久久久久九九精品久 | 中文字幕无码av激情不卡 | 国产热a欧美热a在线视频 | 亚洲一区二区三区国产精华液 | 丰满岳乱妇在线观看中字无码 | 日本成熟视频免费视频 | 99麻豆久久久国产精品免费 | 国产精品久久久久久亚洲毛片 | 狠狠噜狠狠狠狠丁香五月 | 一区二区三区乱码在线 | 欧洲 | 性欧美疯狂xxxxbbbb | 国产亚洲精品久久久久久国模美 | 久久综合给合久久狠狠狠97色 | 国产成人无码专区 | 久久久中文久久久无码 | 亚洲日韩中文字幕在线播放 | 亚洲爆乳精品无码一区二区三区 | 成人精品一区二区三区中文字幕 | 色妞www精品免费视频 | 欧美日韩久久久精品a片 | 精品少妇爆乳无码av无码专区 | 国产精品久久久久7777 | 日欧一片内射va在线影院 | 日本免费一区二区三区最新 | 国产精品怡红院永久免费 | 一本加勒比波多野结衣 | 中文精品久久久久人妻不卡 | 亚洲国产欧美国产综合一区 | 亚洲国产欧美日韩精品一区二区三区 | 无码精品人妻一区二区三区av | 成人无码精品一区二区三区 | 欧美性生交活xxxxxdddd | 免费网站看v片在线18禁无码 | av无码久久久久不卡免费网站 | 99精品国产综合久久久久五月天 | 日本丰满护士爆乳xxxx | 未满成年国产在线观看 | 欧美精品在线观看 | 黑人粗大猛烈进出高潮视频 | 久久久成人毛片无码 | 老熟女重囗味hdxx69 | 中文无码成人免费视频在线观看 | 男人扒开女人内裤强吻桶进去 | 亚洲精品综合一区二区三区在线 | 国产一区二区三区四区五区加勒比 | 婷婷综合久久中文字幕蜜桃三电影 | 麻豆蜜桃av蜜臀av色欲av | 成人精品一区二区三区中文字幕 | 中文字幕无码av波多野吉衣 | 亚洲伊人久久精品影院 | 亚洲国产午夜精品理论片 | 日本饥渴人妻欲求不满 | 最新版天堂资源中文官网 | 亚洲码国产精品高潮在线 | 国产又粗又硬又大爽黄老大爷视 | 日本精品久久久久中文字幕 | 女人被爽到呻吟gif动态图视看 | 日本va欧美va欧美va精品 | 激情爆乳一区二区三区 | 乱码av麻豆丝袜熟女系列 | 国产成人一区二区三区在线观看 | 国产性生大片免费观看性 | 亚洲国产av美女网站 | 天干天干啦夜天干天2017 | 国语自产偷拍精品视频偷 | 在线观看欧美一区二区三区 | 久久精品中文闷骚内射 | 久久国产精品_国产精品 | 人妻体内射精一区二区三四 | 少妇高潮一区二区三区99 | 日韩少妇内射免费播放 | 亚洲日本在线电影 | 久久午夜夜伦鲁鲁片无码免费 | 欧美 丝袜 自拍 制服 另类 | 成人无码影片精品久久久 | 在线a亚洲视频播放在线观看 | 97资源共享在线视频 | 亚洲国产精品无码一区二区三区 | 欧美日韩一区二区免费视频 | 精品 日韩 国产 欧美 视频 | 久久久久成人精品免费播放动漫 | 亚洲精品国产第一综合99久久 | 亚洲熟妇色xxxxx亚洲 | 97se亚洲精品一区 | 欧美激情一区二区三区成人 | 高中生自慰www网站 | 99久久久无码国产aaa精品 | 亚洲熟熟妇xxxx | 国产乱人伦av在线无码 | 国产综合久久久久鬼色 | 国产亚洲人成在线播放 | 亚洲日韩乱码中文无码蜜桃臀网站 | 亚洲啪av永久无码精品放毛片 | 久久久av男人的天堂 | 久久成人a毛片免费观看网站 | 欧美日韩在线亚洲综合国产人 | 97资源共享在线视频 | 又大又黄又粗又爽的免费视频 | 精品国产乱码久久久久乱码 | 性做久久久久久久免费看 | 少妇一晚三次一区二区三区 | 国产av一区二区精品久久凹凸 | 国产精品久久国产精品99 | 精品一区二区三区波多野结衣 | 亚洲无人区午夜福利码高清完整版 | 国产偷抇久久精品a片69 | 中文字幕乱码人妻无码久久 | 在线观看免费人成视频 | 99国产欧美久久久精品 | 国产精品怡红院永久免费 | 曰韩无码二三区中文字幕 | 国产亚洲精品久久久闺蜜 | 精品国产aⅴ无码一区二区 | 无套内谢老熟女 | 国产成人精品久久亚洲高清不卡 | 欧美日韩综合一区二区三区 | 欧美人妻一区二区三区 | 丰满少妇弄高潮了www | 丰满肥臀大屁股熟妇激情视频 | 国产精品人妻一区二区三区四 | 国产又粗又硬又大爽黄老大爷视 | 大肉大捧一进一出视频出来呀 | 精品久久久中文字幕人妻 | 无码乱肉视频免费大全合集 | 国产国产精品人在线视 | 国产黑色丝袜在线播放 | 亚洲中文字幕久久无码 | 无码国产色欲xxxxx视频 | 国产性生交xxxxx无码 | 粉嫩少妇内射浓精videos | 欧美丰满熟妇xxxx性ppx人交 | 日韩欧美中文字幕在线三区 | 亚洲熟妇色xxxxx亚洲 | 亚洲中文字幕va福利 | 久久久国产精品无码免费专区 | 帮老师解开蕾丝奶罩吸乳网站 | 国产偷抇久久精品a片69 | 麻豆蜜桃av蜜臀av色欲av | 午夜无码人妻av大片色欲 | 亚无码乱人伦一区二区 | 人人妻人人澡人人爽欧美一区 | 国产精品鲁鲁鲁 | 久久久久99精品国产片 | 领导边摸边吃奶边做爽在线观看 | 国产情侣作爱视频免费观看 | 真人与拘做受免费视频一 | 日本xxxx色视频在线观看免费 | 免费观看激色视频网站 | 狠狠综合久久久久综合网 | 天干天干啦夜天干天2017 | 国产猛烈高潮尖叫视频免费 | 无码精品人妻一区二区三区av | 国产性生交xxxxx无码 | 精品国产青草久久久久福利 | 精品人人妻人人澡人人爽人人 | 亚洲精品一区二区三区在线观看 | 久精品国产欧美亚洲色aⅴ大片 | 无码av岛国片在线播放 | 亚洲欧洲日本无在线码 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 国产成人人人97超碰超爽8 | 国产综合久久久久鬼色 | 国产成人久久精品流白浆 | 国产精品久久久久9999小说 | 亚洲欧美精品伊人久久 | 少女韩国电视剧在线观看完整 | 久久精品国产一区二区三区肥胖 | 国产另类ts人妖一区二区 | 国产在线精品一区二区高清不卡 | 亚洲欧美日韩成人高清在线一区 | 亚洲精品久久久久久久久久久 | 伦伦影院午夜理论片 | 人人爽人人爽人人片av亚洲 | 欧美激情综合亚洲一二区 | 熟女俱乐部五十路六十路av | 黑人大群体交免费视频 | 激情国产av做激情国产爱 | 狠狠亚洲超碰狼人久久 | 欧美日韩久久久精品a片 | 又粗又大又硬毛片免费看 | 欧美自拍另类欧美综合图片区 | 成年美女黄网站色大免费全看 | 亚洲欧洲无卡二区视頻 | 中文字幕 亚洲精品 第1页 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 特大黑人娇小亚洲女 | 欧美日韩一区二区免费视频 | 97精品国产97久久久久久免费 | 国产va免费精品观看 | 无码人妻丰满熟妇区毛片18 | 97人妻精品一区二区三区 | 免费人成在线观看网站 | 午夜精品久久久久久久 | 久久综合九色综合97网 | 噜噜噜亚洲色成人网站 | 久久国产精品精品国产色婷婷 | 久久天天躁狠狠躁夜夜免费观看 | 亚洲va中文字幕无码久久不卡 | 亚洲中文字幕无码中文字在线 | 国产精品丝袜黑色高跟鞋 | 日韩精品成人一区二区三区 | 国产激情艳情在线看视频 | 亚洲中文字幕无码中字 | 欧洲精品码一区二区三区免费看 | 久久99国产综合精品 | 精品厕所偷拍各类美女tp嘘嘘 | 中文无码伦av中文字幕 | 人人妻人人澡人人爽精品欧美 | 秋霞特色aa大片 | 国产麻豆精品精东影业av网站 | 久久久久久久久蜜桃 | 在线播放亚洲第一字幕 | 亚洲国产成人av在线观看 | 曰本女人与公拘交酡免费视频 | 天天拍夜夜添久久精品 | 国产va免费精品观看 | 天堂а√在线中文在线 | 人人妻人人澡人人爽人人精品浪潮 | 丰满人妻翻云覆雨呻吟视频 | 俺去俺来也在线www色官网 | 免费无码肉片在线观看 | 日本一区二区更新不卡 | 国产特级毛片aaaaaaa高清 | 久久久精品人妻久久影视 | 国内老熟妇对白xxxxhd | 色婷婷综合激情综在线播放 | 国产内射爽爽大片视频社区在线 | 丝袜足控一区二区三区 | 亚洲日韩av一区二区三区四区 | 日本丰满护士爆乳xxxx | 丝袜美腿亚洲一区二区 | 又色又爽又黄的美女裸体网站 | 波多野42部无码喷潮在线 | 中文字幕av伊人av无码av | 亚洲色大成网站www国产 | 国产午夜精品一区二区三区嫩草 | 午夜福利不卡在线视频 | 欧美日韩久久久精品a片 | 亚洲精品成a人在线观看 | 激情人妻另类人妻伦 | 亚洲国产精品一区二区第一页 | 日韩欧美中文字幕在线三区 | 久久久精品人妻久久影视 | 女人被男人躁得好爽免费视频 | 国产精华av午夜在线观看 | 中文字幕 人妻熟女 | 久久国语露脸国产精品电影 | 久久99精品国产麻豆蜜芽 | 久久久www成人免费毛片 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 久久久久久av无码免费看大片 | 成年美女黄网站色大免费视频 | 国产成人亚洲综合无码 | 精品久久久无码中文字幕 | 亚洲aⅴ无码成人网站国产app | 一本精品99久久精品77 | 中文字幕无码日韩欧毛 | 人人爽人人爽人人片av亚洲 | 日韩欧美中文字幕在线三区 | 丰满少妇熟乱xxxxx视频 | 欧洲精品码一区二区三区免费看 | 亚洲乱码中文字幕在线 | 久久国产精品_国产精品 | 人人爽人人爽人人片av亚洲 | 亚洲精品国偷拍自产在线麻豆 | 亚洲高清偷拍一区二区三区 | 亚洲精品成人福利网站 | 天下第一社区视频www日本 | 国产色xx群视频射精 | 亚洲熟熟妇xxxx | 日本乱偷人妻中文字幕 | 久久久久久久久888 | 亚洲中文字幕无码一久久区 | 成熟妇人a片免费看网站 | 国产精品无码永久免费888 | 亚洲国产午夜精品理论片 | 无遮无挡爽爽免费视频 | 国产午夜福利亚洲第一 | 国产人妻久久精品二区三区老狼 | 无套内谢老熟女 | 成人性做爰aaa片免费看不忠 | 精品久久久无码人妻字幂 | 天天av天天av天天透 | 欧美大屁股xxxxhd黑色 | av无码久久久久不卡免费网站 | 人妻少妇精品无码专区动漫 | 日本高清一区免费中文视频 | 永久免费精品精品永久-夜色 | 亚洲精品鲁一鲁一区二区三区 | 成人亚洲精品久久久久 | 天天摸天天透天天添 | 亚洲a无码综合a国产av中文 | 正在播放老肥熟妇露脸 | 日本一区二区更新不卡 | 国产美女精品一区二区三区 | 久久精品国产一区二区三区肥胖 | 一本无码人妻在中文字幕免费 | 纯爱无遮挡h肉动漫在线播放 | 免费无码的av片在线观看 | 一本久久a久久精品vr综合 | 亚洲无人区午夜福利码高清完整版 | 亚洲成熟女人毛毛耸耸多 | av人摸人人人澡人人超碰下载 | 精品国产aⅴ无码一区二区 | 久久精品女人的天堂av | 免费国产成人高清在线观看网站 | 成年女人永久免费看片 | 青青草原综合久久大伊人精品 | 精品国产青草久久久久福利 | 九月婷婷人人澡人人添人人爽 | 粗大的内捧猛烈进出视频 | 国产精品内射视频免费 | 亚洲日本va中文字幕 | 狠狠亚洲超碰狼人久久 | 久久国产精品_国产精品 | 国产亚洲人成a在线v网站 | 曰韩无码二三区中文字幕 | 麻豆国产丝袜白领秘书在线观看 | 纯爱无遮挡h肉动漫在线播放 | 欧美日韩久久久精品a片 | 亚洲码国产精品高潮在线 | 精品一区二区三区波多野结衣 | 精品厕所偷拍各类美女tp嘘嘘 | 亚洲精品午夜无码电影网 | 清纯唯美经典一区二区 | 久久久久99精品成人片 | 人人妻人人澡人人爽精品欧美 | 99精品无人区乱码1区2区3区 | 天堂亚洲2017在线观看 | 久久亚洲国产成人精品性色 | 国产亚洲精品久久久久久 | 理论片87福利理论电影 | 国产成人精品三级麻豆 | 亚洲成熟女人毛毛耸耸多 | 久激情内射婷内射蜜桃人妖 | 精品久久8x国产免费观看 | 天天躁夜夜躁狠狠是什么心态 | 亚洲精品无码国产 | 久久精品国产大片免费观看 | 国产99久久精品一区二区 | 亚洲 激情 小说 另类 欧美 | 久久久成人毛片无码 | 亚洲va中文字幕无码久久不卡 | 综合人妻久久一区二区精品 | 天天燥日日燥 | 欧洲熟妇精品视频 | www成人国产高清内射 | 性开放的女人aaa片 | 亚洲精品鲁一鲁一区二区三区 | 极品尤物被啪到呻吟喷水 | 无码人中文字幕 | 无遮挡国产高潮视频免费观看 | 999久久久国产精品消防器材 | 亚洲国产高清在线观看视频 | 日本熟妇人妻xxxxx人hd | 在线播放无码字幕亚洲 | 久久午夜夜伦鲁鲁片无码免费 | 亚洲日韩一区二区三区 | 99久久久国产精品无码免费 | 精品久久综合1区2区3区激情 | 国产农村乱对白刺激视频 | 亚洲精品一区二区三区在线观看 | 正在播放老肥熟妇露脸 | 狠狠色噜噜狠狠狠7777奇米 | 人人澡人人妻人人爽人人蜜桃 | 熟女少妇人妻中文字幕 | 国产亚洲精品久久久久久久久动漫 | 日韩精品无码一区二区中文字幕 | 欧美成人高清在线播放 | 欧美肥老太牲交大战 | 欧洲vodafone精品性 | 天堂在线观看www | 国产在线精品一区二区高清不卡 | 亚洲色www成人永久网址 | 久久久婷婷五月亚洲97号色 | 久久97精品久久久久久久不卡 | 高清无码午夜福利视频 | 55夜色66夜色国产精品视频 | 3d动漫精品啪啪一区二区中 | 97精品国产97久久久久久免费 | 99久久久国产精品无码免费 | 午夜肉伦伦影院 | 国産精品久久久久久久 | 男女猛烈xx00免费视频试看 | 精品国产福利一区二区 | 日本高清一区免费中文视频 | 99久久久国产精品无码免费 | 精品无码av一区二区三区 | 国产成人综合美国十次 | 欧美35页视频在线观看 | 婷婷综合久久中文字幕蜜桃三电影 | 国产高清av在线播放 | 美女黄网站人色视频免费国产 | а天堂中文在线官网 | 中国女人内谢69xxxxxa片 | 东京一本一道一二三区 | 精品久久久无码人妻字幂 | 久久99国产综合精品 | 丰满人妻精品国产99aⅴ | 久久亚洲a片com人成 | 国产婷婷色一区二区三区在线 | 强开小婷嫩苞又嫩又紧视频 | 97精品人妻一区二区三区香蕉 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 亚洲娇小与黑人巨大交 | 精品国产一区av天美传媒 | 精品无码国产自产拍在线观看蜜 | 精品国产一区二区三区av 性色 | 久久精品女人的天堂av | 亚洲国产精品无码久久久久高潮 | 国产精品亚洲а∨无码播放麻豆 | 四虎国产精品一区二区 | 欧美野外疯狂做受xxxx高潮 | 麻豆国产丝袜白领秘书在线观看 | 99久久久无码国产aaa精品 | 超碰97人人做人人爱少妇 | 天堂а√在线地址中文在线 | 久久久久亚洲精品中文字幕 | 亚洲精品一区二区三区婷婷月 | 自拍偷自拍亚洲精品被多人伦好爽 | 草草网站影院白丝内射 | 97夜夜澡人人双人人人喊 | 日本精品人妻无码免费大全 | 亚洲国产精品无码久久久久高潮 | 精品熟女少妇av免费观看 | 亚洲色欲久久久综合网东京热 | 亚洲欧美日韩综合久久久 | aⅴ在线视频男人的天堂 | 97无码免费人妻超级碰碰夜夜 | 乱码av麻豆丝袜熟女系列 | 日韩欧美群交p片內射中文 | 水蜜桃色314在线观看 | 午夜福利一区二区三区在线观看 | 高清无码午夜福利视频 | 久久国产精品二国产精品 | 国产精品久久久久7777 | 亚洲成av人片天堂网无码】 | 久久国产精品二国产精品 | 中文字幕av无码一区二区三区电影 | 无码人妻精品一区二区三区下载 | 欧美老人巨大xxxx做受 | 成年美女黄网站色大免费视频 | 国产肉丝袜在线观看 | 国产精品久久久久久久9999 | 99久久亚洲精品无码毛片 | 久久 国产 尿 小便 嘘嘘 | 国产99久久精品一区二区 | 亚洲成熟女人毛毛耸耸多 | 97无码免费人妻超级碰碰夜夜 | 欧美人与物videos另类 | 欧美怡红院免费全部视频 | 99视频精品全部免费免费观看 | 99视频精品全部免费免费观看 | av香港经典三级级 在线 | 性欧美videos高清精品 | 一本大道伊人av久久综合 | 自拍偷自拍亚洲精品被多人伦好爽 | 小sao货水好多真紧h无码视频 | 国产精品99久久精品爆乳 | 亚洲欧美国产精品久久 | 亚洲爆乳无码专区 | 亚洲欧洲无卡二区视頻 | 欧美亚洲日韩国产人成在线播放 | 99精品国产综合久久久久五月天 | 无码中文字幕色专区 | 成在人线av无码免观看麻豆 | 狂野欧美性猛交免费视频 | 色综合久久88色综合天天 | 欧美老妇交乱视频在线观看 | 日本精品人妻无码77777 天堂一区人妻无码 | 亚洲 欧美 激情 小说 另类 | 免费人成在线视频无码 | 国产精品亚洲五月天高清 | 最新版天堂资源中文官网 | 无码精品国产va在线观看dvd | 午夜男女很黄的视频 | 国产亚洲tv在线观看 | 色诱久久久久综合网ywww | 亚洲精品中文字幕乱码 | 俺去俺来也在线www色官网 | 中文字幕无码av波多野吉衣 | 欧洲熟妇精品视频 | 小鲜肉自慰网站xnxx | 奇米影视7777久久精品人人爽 | 亚洲精品综合五月久久小说 | 亚洲人交乣女bbw | 牲欲强的熟妇农村老妇女视频 | 小sao货水好多真紧h无码视频 | √8天堂资源地址中文在线 | 麻花豆传媒剧国产免费mv在线 | 亚洲va中文字幕无码久久不卡 | 久久久久久av无码免费看大片 | 亚洲色欲色欲欲www在线 | 国产成人无码a区在线观看视频app | 色五月五月丁香亚洲综合网 | 午夜精品一区二区三区在线观看 | 国产人妻精品一区二区三区 | 国产绳艺sm调教室论坛 | 欧美 亚洲 国产 另类 | 久久久国产精品无码免费专区 | 色综合久久中文娱乐网 | 成人一在线视频日韩国产 | 亚洲中文字幕在线无码一区二区 | 男女爱爱好爽视频免费看 | 国产亚洲欧美日韩亚洲中文色 | 久久国产劲爆∧v内射 | 久久国产精品偷任你爽任你 | 国产精品va在线播放 | 理论片87福利理论电影 | 久久久久久av无码免费看大片 | 国产热a欧美热a在线视频 | 搡女人真爽免费视频大全 | 亚洲中文无码av永久不收费 | 欧美变态另类xxxx | 天天综合网天天综合色 | 中文字幕乱码人妻无码久久 | 好男人社区资源 | 国产成人一区二区三区在线观看 | 精品国产精品久久一区免费式 | 久久久久久亚洲精品a片成人 | 久久99精品久久久久久 | 国产无遮挡又黄又爽免费视频 | 亚洲精品无码人妻无码 | 水蜜桃色314在线观看 | 日韩av激情在线观看 | 精品成在人线av无码免费看 | 18无码粉嫩小泬无套在线观看 | 超碰97人人做人人爱少妇 | 精品成人av一区二区三区 | 日日夜夜撸啊撸 | 六月丁香婷婷色狠狠久久 | 精品国产精品久久一区免费式 | 中文字幕精品av一区二区五区 | 国内精品久久久久久中文字幕 | 亚洲一区二区三区国产精华液 | 久久久精品成人免费观看 | 内射白嫩少妇超碰 | 精品一区二区三区波多野结衣 | 国产激情一区二区三区 | 男女性色大片免费网站 | 在线天堂新版最新版在线8 | 内射巨臀欧美在线视频 | 国产午夜精品一区二区三区嫩草 | 伊在人天堂亚洲香蕉精品区 | 国产性生交xxxxx无码 | 色一情一乱一伦一区二区三欧美 | 少妇一晚三次一区二区三区 | 成人性做爰aaa片免费看不忠 | 国产精品-区区久久久狼 | 又紧又大又爽精品一区二区 | 亚洲成av人片天堂网无码】 | 性做久久久久久久免费看 | 精品一二三区久久aaa片 | a国产一区二区免费入口 | 东京热无码av男人的天堂 | 无码av中文字幕免费放 | 国产精品亚洲lv粉色 | 久久久久成人片免费观看蜜芽 | 久久无码中文字幕免费影院蜜桃 | 少妇被黑人到高潮喷出白浆 | 国产精品久久久久久亚洲影视内衣 | 精品午夜福利在线观看 | 国产精品嫩草久久久久 | 国产凸凹视频一区二区 | 亚洲区小说区激情区图片区 | 超碰97人人做人人爱少妇 | 四虎影视成人永久免费观看视频 | 狠狠色欧美亚洲狠狠色www | 玩弄人妻少妇500系列视频 | 国产精品久久久久久亚洲影视内衣 | 国产成人精品三级麻豆 | 伊人久久大香线蕉亚洲 | 伊人久久婷婷五月综合97色 | 欧美性生交活xxxxxdddd | 国产疯狂伦交大片 | 动漫av网站免费观看 | 精品无码国产一区二区三区av | 亚洲精品国偷拍自产在线观看蜜桃 | 欧美肥老太牲交大战 | 一本久道久久综合婷婷五月 | 色综合久久88色综合天天 | 日韩精品乱码av一区二区 | 又紧又大又爽精品一区二区 | 国内丰满熟女出轨videos | 无码人妻出轨黑人中文字幕 | 亚洲精品成人福利网站 | 黑森林福利视频导航 | 亚洲精品综合一区二区三区在线 | 波多野结衣一区二区三区av免费 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 色窝窝无码一区二区三区色欲 | 男人扒开女人内裤强吻桶进去 | 亚洲中文字幕va福利 | 成人无码影片精品久久久 | 亚洲日韩av一区二区三区中文 | www国产亚洲精品久久网站 | 18禁黄网站男男禁片免费观看 | 欧美兽交xxxx×视频 | 高潮毛片无遮挡高清免费 | 国产亚洲精品久久久久久国模美 | 桃花色综合影院 | 亚洲精品国偷拍自产在线麻豆 | 久久午夜无码鲁丝片 | 精品国产一区二区三区av 性色 | 免费人成在线视频无码 | 国产一区二区不卡老阿姨 | 午夜福利不卡在线视频 | 西西人体www44rt大胆高清 | 四虎影视成人永久免费观看视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久久久人妻一区精品色欧美 | 丰满妇女强制高潮18xxxx | 无码人妻精品一区二区三区下载 | 中文字幕无码免费久久9一区9 | 国产精品无码一区二区桃花视频 | 亚洲 a v无 码免 费 成 人 a v | 国产av无码专区亚洲a∨毛片 | 日韩精品无码一区二区中文字幕 | 成 人 网 站国产免费观看 | 国产口爆吞精在线视频 | 国产乱人伦app精品久久 国产在线无码精品电影网 国产国产精品人在线视 | 国产精品久久久久9999小说 | 黑人巨大精品欧美一区二区 | 99视频精品全部免费免费观看 | аⅴ资源天堂资源库在线 | 骚片av蜜桃精品一区 | 久久无码中文字幕免费影院蜜桃 | 色综合视频一区二区三区 | 欧美激情一区二区三区成人 | 中文久久乱码一区二区 | 老司机亚洲精品影院无码 | 久久亚洲日韩精品一区二区三区 | 精品久久久无码人妻字幂 | 无码中文字幕色专区 | 水蜜桃av无码 | 国产va免费精品观看 | 国产精品嫩草久久久久 | 国产成人综合色在线观看网站 | 久久国语露脸国产精品电影 | 夜夜影院未满十八勿进 | 国产一区二区三区日韩精品 | 无码人妻av免费一区二区三区 | 噜噜噜亚洲色成人网站 | 色情久久久av熟女人妻网站 | 日产国产精品亚洲系列 | 国产在线一区二区三区四区五区 | 国产精品国产三级国产专播 | 在线播放免费人成毛片乱码 | 色综合久久中文娱乐网 | 亚洲欧美精品aaaaaa片 | 精品国产福利一区二区 | 99riav国产精品视频 | 欧洲vodafone精品性 | 国产精品亚洲а∨无码播放麻豆 | 日韩少妇白浆无码系列 | 中文字幕无码人妻少妇免费 | 色 综合 欧美 亚洲 国产 | 特级做a爰片毛片免费69 | 久久久亚洲欧洲日产国码αv | 久久精品人人做人人综合 | 性色欲情网站iwww九文堂 | 国产成人精品视频ⅴa片软件竹菊 | 女人高潮内射99精品 | 中文字幕无码av波多野吉衣 | 亚洲色大成网站www国产 | 无码国模国产在线观看 | 欧美人与禽zoz0性伦交 | 99精品视频在线观看免费 | 中文字幕中文有码在线 | 亚洲熟女一区二区三区 | 疯狂三人交性欧美 | 成年女人永久免费看片 | 国产乱人无码伦av在线a | 色婷婷综合中文久久一本 | 乌克兰少妇性做爰 | 无码av岛国片在线播放 | 亚洲区欧美区综合区自拍区 | 欧美 亚洲 国产 另类 | 少妇性俱乐部纵欲狂欢电影 | 成 人影片 免费观看 | 国产三级久久久精品麻豆三级 | 国内少妇偷人精品视频免费 | 日本一区二区三区免费播放 | 蜜臀av在线播放 久久综合激激的五月天 | 国产精品久久久 | 男女猛烈xx00免费视频试看 | 国产极品视觉盛宴 | 亚洲国产精品毛片av不卡在线 | 狠狠亚洲超碰狼人久久 | 亚洲色欲色欲天天天www | 亚洲国产精品久久久久久 | 精品一区二区三区无码免费视频 | 日本精品久久久久中文字幕 | 亚洲小说春色综合另类 | 久久精品中文闷骚内射 | 亚洲毛片av日韩av无码 | 久久综合狠狠综合久久综合88 | 无码一区二区三区在线观看 | 日韩精品一区二区av在线 | 久久这里只有精品视频9 | 午夜理论片yy44880影院 | √天堂资源地址中文在线 | 亚洲成a人片在线观看日本 | 久久久中文久久久无码 | 国产成人精品无码播放 | 中文字幕无码免费久久9一区9 | 999久久久国产精品消防器材 | 中文字幕人妻无码一区二区三区 | www国产精品内射老师 | 亚洲精品久久久久avwww潮水 | 欧美35页视频在线观看 | 无码人妻久久一区二区三区不卡 | 精品久久久无码人妻字幂 | 国产sm调教视频在线观看 | av无码电影一区二区三区 | 青青草原综合久久大伊人精品 | 中文字幕乱码中文乱码51精品 | 荡女精品导航 | 精品无码av一区二区三区 | 日日碰狠狠躁久久躁蜜桃 | 欧美日本精品一区二区三区 | 久久久久se色偷偷亚洲精品av | 99精品国产综合久久久久五月天 | 久久99精品久久久久久动态图 | 精品久久8x国产免费观看 | 中文字幕无码人妻少妇免费 | 好男人社区资源 | 国产激情精品一区二区三区 | 日韩人妻无码中文字幕视频 | 国产精品二区一区二区aⅴ污介绍 | 99久久精品国产一区二区蜜芽 | 日韩人妻无码中文字幕视频 | 任你躁国产自任一区二区三区 | 欧美老熟妇乱xxxxx | 久久精品国产大片免费观看 | 久久精品人妻少妇一区二区三区 | 国内少妇偷人精品视频 | 麻花豆传媒剧国产免费mv在线 | 国产麻豆精品精东影业av网站 | 日日碰狠狠躁久久躁蜜桃 | www国产亚洲精品久久网站 | 欧美人妻一区二区三区 | 高潮毛片无遮挡高清免费视频 | 人妻插b视频一区二区三区 | 自拍偷自拍亚洲精品被多人伦好爽 | 极品尤物被啪到呻吟喷水 | 精品国产乱码久久久久乱码 | 好屌草这里只有精品 | 亚洲中文字幕久久无码 | 日本熟妇大屁股人妻 | 国产精品国产自线拍免费软件 | 亚洲人成网站免费播放 | 日韩人妻无码一区二区三区久久99 | 国产亚洲精品久久久闺蜜 | 狠狠亚洲超碰狼人久久 | 久久久精品欧美一区二区免费 | 国产成人无码av一区二区 | а√天堂www在线天堂小说 | 日韩视频 中文字幕 视频一区 | 动漫av一区二区在线观看 | 国产人妻精品一区二区三区 | 日日噜噜噜噜夜夜爽亚洲精品 | 四虎永久在线精品免费网址 | 亚洲国产成人a精品不卡在线 | 亚洲国产高清在线观看视频 | 日韩欧美中文字幕在线三区 | 无码精品人妻一区二区三区av | 欧美 日韩 人妻 高清 中文 | 高潮毛片无遮挡高清免费视频 | 国产精品二区一区二区aⅴ污介绍 | 国产极品视觉盛宴 | 给我免费的视频在线观看 | 日日摸天天摸爽爽狠狠97 | 搡女人真爽免费视频大全 | 欧美高清在线精品一区 | 麻花豆传媒剧国产免费mv在线 | 日本精品人妻无码免费大全 | 成人无码视频免费播放 | 国产真实乱对白精彩久久 | 亚洲小说图区综合在线 | 国产精品久久久久久亚洲影视内衣 | 国产尤物精品视频 | 精品乱码久久久久久久 | 欧美色就是色 | 丰腴饱满的极品熟妇 | 亚洲精品成人av在线 | 131美女爱做视频 | 精品少妇爆乳无码av无码专区 | 中文字幕av无码一区二区三区电影 | 亚洲国产精品久久久久久 | 国内精品久久毛片一区二区 | 国产女主播喷水视频在线观看 | 骚片av蜜桃精品一区 | 人人爽人人澡人人高潮 | 日本精品人妻无码免费大全 | 精品一区二区三区波多野结衣 | 久久亚洲日韩精品一区二区三区 | 亚洲精品一区国产 | 99久久久无码国产aaa精品 | 日本高清一区免费中文视频 | 欧美激情内射喷水高潮 | 骚片av蜜桃精品一区 | 少妇高潮一区二区三区99 | 亚洲 激情 小说 另类 欧美 | 97久久精品无码一区二区 | 国产色xx群视频射精 | 欧美真人作爱免费视频 | 国内少妇偷人精品视频 | 久久久婷婷五月亚洲97号色 | 亚洲人成影院在线无码按摩店 | 又紧又大又爽精品一区二区 | 一本久道久久综合狠狠爱 | 婷婷丁香五月天综合东京热 | 帮老师解开蕾丝奶罩吸乳网站 | 国产99久久精品一区二区 | 丁香花在线影院观看在线播放 | 久久综合香蕉国产蜜臀av | 久久综合九色综合欧美狠狠 | 乱人伦人妻中文字幕无码 | 无码吃奶揉捏奶头高潮视频 | 日日鲁鲁鲁夜夜爽爽狠狠 | 精品久久久中文字幕人妻 | www国产亚洲精品久久网站 | 波多野结衣一区二区三区av免费 | 色偷偷人人澡人人爽人人模 | 亚洲午夜福利在线观看 | 色一情一乱一伦 | 午夜丰满少妇性开放视频 | 无码一区二区三区在线 | 水蜜桃色314在线观看 | 成人无码精品一区二区三区 | 国产av一区二区精品久久凹凸 | 中文字幕无码乱人伦 | 国产手机在线αⅴ片无码观看 | 国内精品一区二区三区不卡 | 无遮挡国产高潮视频免费观看 | а√资源新版在线天堂 | 色婷婷综合激情综在线播放 | 国产人妻久久精品二区三区老狼 | 国产片av国语在线观看 | 领导边摸边吃奶边做爽在线观看 | 国产精品嫩草久久久久 | 久久久久人妻一区精品色欧美 | 成人影院yy111111在线观看 | 天堂亚洲免费视频 | 国产精品办公室沙发 | 波多野42部无码喷潮在线 | 色综合久久久久综合一本到桃花网 | 玩弄中年熟妇正在播放 | 99久久人妻精品免费一区 | 亚洲国产成人av在线观看 | 蜜臀av在线观看 在线欧美精品一区二区三区 | 小sao货水好多真紧h无码视频 | 在线观看国产一区二区三区 | a在线观看免费网站大全 | 动漫av网站免费观看 | 在线精品亚洲一区二区 | 国产精华av午夜在线观看 | 一本色道婷婷久久欧美 | 国产熟妇高潮叫床视频播放 | 午夜成人1000部免费视频 | 久久精品国产亚洲精品 | 亚洲精品中文字幕久久久久 | 四虎国产精品免费久久 | 国产猛烈高潮尖叫视频免费 | 漂亮人妻洗澡被公强 日日躁 | 人人妻人人澡人人爽欧美一区九九 | 亚洲精品一区三区三区在线观看 | 红桃av一区二区三区在线无码av | 久精品国产欧美亚洲色aⅴ大片 | 超碰97人人射妻 | 亚洲欧美日韩国产精品一区二区 | 无码人妻精品一区二区三区不卡 | 大地资源网第二页免费观看 | 欧美日韩色另类综合 | www成人国产高清内射 | 男女超爽视频免费播放 | 人妻无码αv中文字幕久久琪琪布 | 欧美丰满熟妇xxxx性ppx人交 | 无码精品人妻一区二区三区av | 一本久道高清无码视频 | 欧美野外疯狂做受xxxx高潮 | 蜜桃臀无码内射一区二区三区 | 中文字幕无码免费久久99 | 高清不卡一区二区三区 | 亚洲日韩中文字幕在线播放 | 欧美自拍另类欧美综合图片区 | 天天摸天天透天天添 | 国产内射老熟女aaaa | 欧美老人巨大xxxx做受 | 国产激情综合五月久久 | 欧美精品无码一区二区三区 | 超碰97人人射妻 | 大肉大捧一进一出好爽视频 | 国产激情精品一区二区三区 | 亚洲国产精品久久久天堂 | 国产av一区二区精品久久凹凸 | 午夜精品一区二区三区的区别 | 老子影院午夜精品无码 | 97夜夜澡人人爽人人喊中国片 | 国产人妻久久精品二区三区老狼 | 成人影院yy111111在线观看 | 亚洲日韩av一区二区三区中文 | 理论片87福利理论电影 | 国产色xx群视频射精 | 少妇被粗大的猛进出69影院 | 亚洲精品成a人在线观看 | 男女下面进入的视频免费午夜 | yw尤物av无码国产在线观看 | 自拍偷自拍亚洲精品被多人伦好爽 | 乌克兰少妇xxxx做受 | 日韩av无码一区二区三区不卡 | 麻豆国产丝袜白领秘书在线观看 | 亚洲a无码综合a国产av中文 | 九一九色国产 | 国产精品久久久 | 日韩av无码一区二区三区不卡 | 四虎影视成人永久免费观看视频 | 亚洲精品美女久久久久久久 | 久久久www成人免费毛片 | 曰本女人与公拘交酡免费视频 | 欧美35页视频在线观看 | 亚洲日本va午夜在线电影 | 99久久99久久免费精品蜜桃 | 一本精品99久久精品77 | 人人妻人人澡人人爽欧美一区 | 女高中生第一次破苞av | 丝袜 中出 制服 人妻 美腿 | 成人欧美一区二区三区黑人 | 99精品久久毛片a片 | 久久亚洲中文字幕无码 | 激情国产av做激情国产爱 | 亚洲综合无码一区二区三区 | 无码人妻久久一区二区三区不卡 | 亚洲色偷偷偷综合网 | 九一九色国产 | 亚洲狠狠婷婷综合久久 | 久久精品99久久香蕉国产色戒 | 亚洲色www成人永久网址 | 在线看片无码永久免费视频 | 欧美激情一区二区三区成人 | 亚洲s色大片在线观看 | 黑人玩弄人妻中文在线 | 国语精品一区二区三区 | 亚洲一区二区三区含羞草 | 亚洲人成网站色7799 | 午夜福利电影 | 小泽玛莉亚一区二区视频在线 | 亚洲天堂2017无码 | 熟女少妇人妻中文字幕 | 5858s亚洲色大成网站www | 国产超级va在线观看视频 | 九一九色国产 | 国产精品va在线观看无码 | 高清不卡一区二区三区 | 宝宝好涨水快流出来免费视频 | 亚洲色在线无码国产精品不卡 | 亚洲第一网站男人都懂 | 国产成人无码a区在线观看视频app | 九月婷婷人人澡人人添人人爽 | 妺妺窝人体色www婷婷 | 麻豆成人精品国产免费 | 日韩成人一区二区三区在线观看 | 精品午夜福利在线观看 | 99久久人妻精品免费一区 | 白嫩日本少妇做爰 | 麻豆成人精品国产免费 | 无码帝国www无码专区色综合 | 成人精品天堂一区二区三区 | 高清国产亚洲精品自在久久 | 在教室伦流澡到高潮hnp视频 | 小sao货水好多真紧h无码视频 | 曰韩少妇内射免费播放 | 国产综合久久久久鬼色 | 久久精品国产99久久6动漫 | 97久久超碰中文字幕 | 无码中文字幕色专区 | 人妻无码久久精品人妻 | 国产人妖乱国产精品人妖 | 在教室伦流澡到高潮hnp视频 | 亚洲国产精品无码一区二区三区 | 波多野结衣av在线观看 | 国产午夜无码视频在线观看 | 国产肉丝袜在线观看 | 亚无码乱人伦一区二区 | 国产精品99爱免费视频 | а√资源新版在线天堂 | 天干天干啦夜天干天2017 | 午夜精品一区二区三区的区别 | 国产亚洲日韩欧美另类第八页 | 国产亚洲精品久久久久久久久动漫 | 自拍偷自拍亚洲精品10p | 免费国产成人高清在线观看网站 | 亚洲欧美国产精品专区久久 | 日韩精品无码一区二区中文字幕 | 日本丰满熟妇videos | 国产绳艺sm调教室论坛 | 人人妻人人澡人人爽欧美精品 | 亚洲va中文字幕无码久久不卡 | 国产精品va在线播放 | 99久久亚洲精品无码毛片 | 爆乳一区二区三区无码 | 国产精品久久久久久久影院 | 亚洲精品久久久久久一区二区 | 中文字幕乱码人妻二区三区 | 国产成人精品视频ⅴa片软件竹菊 | 亚洲一区二区三区 | 精品少妇爆乳无码av无码专区 | 成人aaa片一区国产精品 | 欧美日韩一区二区三区自拍 | 免费人成在线视频无码 | 色一情一乱一伦一区二区三欧美 | 全黄性性激高免费视频 | 四虎永久在线精品免费网址 | 久久久国产精品无码免费专区 | 欧美三级a做爰在线观看 | 麻豆果冻传媒2021精品传媒一区下载 | www成人国产高清内射 | 久久久久亚洲精品中文字幕 | 老司机亚洲精品影院无码 | av无码电影一区二区三区 | 麻豆蜜桃av蜜臀av色欲av | 美女毛片一区二区三区四区 | 欧美freesex黑人又粗又大 | 牲欲强的熟妇农村老妇女 | 国产亚洲精品久久久久久久久动漫 | 国产成人无码区免费内射一片色欲 | 天海翼激烈高潮到腰振不止 | 中文字幕无线码 | 亚洲爆乳大丰满无码专区 | 精品无人国产偷自产在线 | 国产综合色产在线精品 | 国产 浪潮av性色四虎 | 久久久无码中文字幕久... | 欧美精品一区二区精品久久 | 久久精品中文字幕大胸 | 一区二区三区高清视频一 | 亚洲国产精品无码一区二区三区 | 日韩精品无码一本二本三本色 | 露脸叫床粗话东北少妇 | 国产色在线 | 国产 | 成人一在线视频日韩国产 | 7777奇米四色成人眼影 | 久久婷婷五月综合色国产香蕉 | 波多野结衣av一区二区全免费观看 | 99久久久国产精品无码免费 | 波多野结衣乳巨码无在线观看 | 水蜜桃av无码 | 久久精品女人天堂av免费观看 | 国产9 9在线 | 中文 | 狠狠色丁香久久婷婷综合五月 | 内射欧美老妇wbb | 在线a亚洲视频播放在线观看 | 欧美精品免费观看二区 | 午夜精品久久久内射近拍高清 | 国产精品无码久久av |