您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關C++ OpenCV怎么實現卡片截取功能,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
實現效果
今天我照了一張自己健身卡的圖片,然后想到實現整體切邊的效果,先上一下源圖
最終我們想到實現在照片中只保留卡這塊的部分。
代碼演示
我們再新建一個項目名為opencv--qiebian,按照配置屬性(VS2017配置OpenCV通用屬性),然后在源文件寫入#include和main方法.
上面我們把加載出來的圖片用resize來調整了一下大小,一開始加載出來超過滿屏了,不方便我們處理。
第一步 先把圖片轉為灰度圖
顯示效果為
第二步 用Canny邊緣提取
我們來看看顯示效果
可以看到右邊就是我們通過邊緣提取后的圖片效果
第三步 發現尋找輪廓
運行后再看看效果
可以看出來,我們邊緣提取后找到了1332個輪廓,這個輪廓中我們只需要找到我們想到的卡信息,所以我們就來到下一步
第四步 定義最小的輪廓寬高,畫出想要的輪廓
可以看到圖中卡片占了圖片一半以上,所以我們可以直接考慮輪廓的大小大于源圖像一半就是我們要少的輪廓了,其余的輪廓就可以忽略了,這樣可以節省很多時間,代碼如下:
然后我們看看運行效果
可以看出,我們要找到矩形完全不是我們想要的結果,在紅色的輪廓里面發現卡片和桌面上的紋理連到一起了,說明我們在Canny邊緣提取的時候需要進行二值化處理,去掉一些不用的結果
第五步 對源圖像進行Canny閾值重新修改看看
我們回到Canny邊緣提取那,把邊緣提取的閾值重修改一下
然后我們重新運行起來看看什么效果
發現右邊通過賦值后不像原來桌面上那么多紋理了,但是從左邊獲取的矩形框后發現也完全不是我們想要的東西。要怎么解決這個問題呢?
一開始我想過了在Canny邊緣提取前先二值化操作一下,最終倒是實現了,但是這個要不停的修改閾值參數,不太方便,還有別的什么辦法呢?這時候我想起來,剛開始學最基本的形態學操作的時候用到的,開操作和閉操作。我們這就來試一下,根據上面的情況,我選擇的閉操作,也就是先膨脹后腐蝕的效果
然后我們再來看看運行的效果
經過閉操作后,可以看出右邊的圖我們過濾掉了非常多沒有必要的東西,也獲取到了最后我們的綠色畫出的矩形框,自我滿足了一下!!!!
第六步 提取到我們要的圖像
我們先修改一下上面定義的參數,這樣下在我們截取的時候就可以用到這個矩形了,下面是我們在復制一份src_gray,因為原圖中src我們已經畫上紅色和綠色線了,畫之前先存一個備份到src_gray里。
然后我們提取最后生成的矩形
最后我們看看生成的結果
右邊就是我們完美截取的卡片圖像,成功~~~~
總結一下實現流程
加載圖片
轉為灰度圖
圖像高斯模糊
進行閉操作(先膨脹后腐蝕)
Canny邊緣提取
尋找輪廓
輪廓中查找符合要求的項
獲取上一步中對應項的最小矩形
從源圖像中截取最小矩形生成新圖片
以上是我自己實驗生成的效果,如果有更好的方法請消息我,畢竟我也是初學者~~
main單元代碼
#include <opencv2\opencv.hpp>
#include <iostream>
cv::Mat src, src_gray, dst;
const char* imgsrc = "源圖"; const char* imgdst = "結果圖";
int main(int argc, char** argv) {
src = cv::imread("E:/DCIM/testcard.jpg");
if (src.empty()) {
printf("could not read image....\n");
getchar();
return -1;
}
//由于加載圖像有點大,我們先調整圖像的大小為寬500,高300
cv::resize(src, src, cv::Size(500, 300));
cv::imshow(imgsrc, src);
//把源圖轉為灰度圖
cv::cvtColor(src, src_gray, CV_BGR2GRAY);
cv::imshow(imgdst, src_gray);
//高斯模糊后加Canny邊緣提取
cv::GaussianBlur(src_gray, dst, cv::Size(3, 3), 0.5, 0.5, 4);
//定義結構元素
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT,
cv::Size(5, 5), cv::Point(-1, -1));
//閉操作
cv::morphologyEx(dst, dst, CV_MOP_CLOSE, element);
//Canny邊緣提取
cv::Canny(dst, dst, 120, 255);
//定義輪廓點及查找輪廓
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
//尋找輪廓
cv::findContours(dst, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
//打印出一共找到了多少個輪廓
printf("contours count:%d\n", contours.size());
//定義要找的輪廓最小的寬高
int minw = dst.cols*0.5;
int minh = dst.rows*0.5;
//定義矩形的四個點
cv::RotatedRect minRect;
cv::Point2f vertices[4];
for (size_t t = 0; t < contours.size(); t++) {
//尋找最小矩形
minRect = cv::minAreaRect(contours[t]);
//獲取傾斜角度
double degree = abs(minRect.angle);
//判斷最小矩形太于我們設置的最小寬和高在獲取數據
if (minRect.size.width > minw && minRect.size.height > minh) {
printf("current rect: %d\n", t);
printf("current angle : %f\n", degree);
//在源圖像上用紅色畫出輪廓樣
src.copyTo(src_gray);//先復制一份src到src_gray里面,下面備用
cv::drawContours(src, contours, t, cv::Scalar(0, 0, 255),
1,8,hierarchy,0);
//在源圖像上用綠色畫出矩形框,定義了4個點,然后用直線畫4個點
minRect.points(vertices);
for (int i = 0; i < 4; i++) {
cv::line(src, vertices[i], vertices[(i + 1) % 4],
cv::Scalar(0, 255, 0));
}
break;
}
}
cv::imshow(imgsrc, src);
//根據獲取的最小矩形截取出圖像顯示出來
cv::Rect rect = minRect.boundingRect();
dst = src_gray(rect);
cv::imshow(imgdst, dst);
cv::waitKey(0);
return 0;
}
關于“C++ OpenCV怎么實現卡片截取功能”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。