对一张静态图片的识别
首先請(qǐng)出我們的主角
我們今天要識(shí)別的就是這張圖片,然后首先我們來看看最后的識(shí)別效果:
雖然識(shí)別出來之后畫的標(biāo)記不是很好,但是只要位置信息出來了,畫標(biāo)記其實(shí)是次要的了。
預(yù)備知識(shí)
這里先介紹一下用到的OpenCV中的名詞(有函數(shù)有類)
Mat:類名,用于儲(chǔ)存圖像
namedWindow:使imshow函數(shù)展示的圖片窗口大小可調(diào)
imshow:展示圖片,并自定義圖片窗口名
RotatedRect:旋轉(zhuǎn)矩形,類名
Point2f:一個(gè)點(diǎn),點(diǎn)的兩個(gè)坐標(biāo)為float型變量
points:返回旋轉(zhuǎn)矩形的四個(gè)頂點(diǎn)
line:連線函數(shù),參數(shù)的意義為:繪制的圖片,點(diǎn)1,點(diǎn)2,線的顏色,線的寬度
cvtColor:將圖片轉(zhuǎn)化為灰度圖,三個(gè)參數(shù)的含義為:輸入圖片,輸出圖片,轉(zhuǎn)換的細(xì)節(jié)(我也剛學(xué),建議csdn)
threshold:將圖片轉(zhuǎn)化為灰度圖:五個(gè)參數(shù)的含義為:輸入圖片,輸出圖片,亮度下界,亮度上界(上下界之中的像素會(huì)被置為白色,其余為黑色),轉(zhuǎn)化細(xì)節(jié)(不了解,同上^ 3^)
split:人如其名,將一張圖片的RGB分裂開來,以BGR的順序存在Mat數(shù)組中(便于后面的尋找顏色位置)
subtract:做減法,不過對(duì)象為兩張圖片,三個(gè)參數(shù)為:被減數(shù),減數(shù),差
不過這里需要注意的是,RoboMaster里面只有兩種裝甲板,紅色和藍(lán)色,紅色我們就紅減藍(lán),藍(lán)色我們就藍(lán)減紅
getStructuringElement:的意義是創(chuàng)建一個(gè)用于膨脹操作的圖形,兩個(gè)參數(shù)的含義是:圖形類型(有矩形,橢圓啥的),大小
dilate:膨脹操作,三個(gè)參數(shù)的含義為:輸入圖像,輸出圖像,膨脹用的圖形
Point:表示一個(gè)點(diǎn)
findContours:根據(jù)二值圖片,尋找二值位置的輪廓,四個(gè)參數(shù)的含義為:輸入圖片,儲(chǔ)存輪廓容器,后面兩個(gè)是找輪廓的選項(xiàng)(我也不是很了解)
auto:這個(gè)不用多說哈
minAreaRect:找到能夠裝下這個(gè)輪廓的最小矩形
waitKey:設(shè)置展示圖片多久自動(dòng)關(guān)閉窗口,單位為毫秒,若為0,則為手動(dòng)關(guān)閉
然后我們一步步介紹識(shí)別步驟
(所有實(shí)現(xiàn)基于VS2017+OpenCV4.1.1)
首先我們需要讀入圖片,用庫函數(shù)imread讀入,我們的圖片文件需要與main文件在同一位置,不然我這樣讀取會(huì)報(bào)錯(cuò)
然后對(duì)其進(jìn)行預(yù)處理(傳入pretreat函數(shù)中),預(yù)處理的目的是得到一張經(jīng)過膨脹操作后的二值圖,再用后續(xù)的操作得到輪廓并畫出
現(xiàn)在我們先介紹pretreat函數(shù):
首先我們將傳入的圖片轉(zhuǎn)換為一個(gè)灰度圖
cvtColor(raw, grey, COLOR_BGR2GRAY);
然后轉(zhuǎn)化為二值圖
threshold(grey, bigrey, 150, 255, THRESH_BINARY);
再將原圖RGB分離
split(raw, channel);
將B通道減去R通道
subtract(channel[0], channel[2], sub_br);
將相減之后的圖片二值化
threshold(sub_br, sub_br, 110, 255, THRESH_BINARY);
創(chuàng)建一個(gè)用于膨脹的圖形
Mat element1 = getStructuringElement(MORPH_RECT, Size(3, 3));
進(jìn)行膨脹操作
dilate(sub_br, sub_br, element1);
ret = sub_br & bigrey;這一句,我們用原圖 灰度二值 之后的圖片與(&)上原圖 通道相減二值膨脹 之后的圖片,提取出較為可信的候選區(qū)域后,再進(jìn)行膨脹
創(chuàng)建另一個(gè)用于膨脹的圖片
Mat element2 = getStructuringElement(MORPH_RECT, Size(2, 2));
對(duì)我們與操作之后的結(jié)果進(jìn)行膨脹操作
dilate(ret, ret, element2);
然后將ret作為結(jié)果傳出
可能會(huì)很疑惑,這些參數(shù)都是怎么來的
沒錯(cuò)都是一個(gè)個(gè)試出來的,換了圖片就不一定管用了
然后介紹一下fixarmor函數(shù)(后續(xù)的展示基于原圖)
其實(shí)這張圖經(jīng)過預(yù)處理之后還會(huì)剩余很多的不需要的白色色塊,這個(gè)時(shí)候就需要我們用匹配進(jìn)行取舍,只有能夠配對(duì)的我們才將其保留下來
還有就是,這里的匹配操作的時(shí)間復(fù)雜度是 O(n2),我說實(shí)話我不知道有沒有更好的匹配方法
contour:我們儲(chǔ)存輪廓的容器,但是我不知道為什么需要這么創(chuàng)建(指模板參數(shù))考ccf差點(diǎn)坑死我(指創(chuàng)建方式)
rect:存我們匹配后的所有矩形
ret:最后配對(duì)成功時(shí),會(huì)以pair的形式存在ret中
findContours(img, contour, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);找輪廓
然后將輪廓弄成矩形后,存在rect中
(這里用找到的temp畫的圖)
然后雙重for,匹配燈條(匹配完之后就是我們最后的結(jié)果,所以不展示了)
我這里用了角度,面積,長(zhǎng)寬比進(jìn)行篩選
(除了長(zhǎng)寬比需要用取出的長(zhǎng)除取出的寬之外,其余兩個(gè)都是成員變量)
后面就是匹配,沒錯(cuò)參數(shù)也是我一個(gè)個(gè)試出來的
最后是源碼:(這個(gè)沒有分文件編寫
#include<opencv2/opencv.hpp> #include<iostream> #include<vector> #include<cmath> using namespace std; using namespace cv;void show(Mat img, string name) {namedWindow(name, 0);imshow(name, img);return; }void drawrect(Mat &img, RotatedRect ob) {Point2f v[4];ob.points(v);for (int i = 0; i < 4; i++)line(img, v[i], v[(i + 1) % 4], Scalar(0, 255, 0), 1);return; }void drawtarget(Mat &img, RotatedRect ob1, RotatedRect ob2) {Point2f v1[4], v2[4];ob1.points(v1);ob2.points(v2);line(img, v1[0], v1[1], Scalar(0, 255, 0), 1);line(img, v1[0], v2[3], Scalar(0, 255, 0), 1);line(img, v2[2], v1[1], Scalar(0, 255, 0), 1);line(img, v2[2], v2[3], Scalar(0, 255, 0), 1);return; }Mat pretreat(Mat raw) {Mat grey;cvtColor(raw, grey, COLOR_BGR2GRAY);Mat bigrey;threshold(grey, bigrey, 150, 255, THRESH_BINARY);Mat channel[3];split(raw, channel);Mat sub_br;subtract(channel[0], channel[2], sub_br);threshold(sub_br, sub_br, 110, 255, THRESH_BINARY);Mat element1 = getStructuringElement(MORPH_RECT, Size(3, 3));dilate(sub_br, sub_br, element1);Mat ret;ret = sub_br & bigrey;Mat element2 = getStructuringElement(MORPH_RECT, Size(2, 2));dilate(ret, ret, element2);return ret; }void fixarmor(Mat &raw,Mat img) {vector<vector<Point>> contour;vector<RotatedRect> rect,finall;vector<pair<RotatedRect, RotatedRect>> ret;findContours(img, contour, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);for (auto x : contour){RotatedRect temp = minAreaRect(x);rect.push_back(temp);}for (auto x : rect){for (auto y : rect){double xangle, yangle, xarea, yarea, xrate, yrate;xarea = x.size.area();xangle = x.angle;yarea = y.size.area();yangle = y.angle;xrate = x.size.height / x.size.width;yrate = y.size.height / y.size.width;if (xarea == yarea) continue;if (xangle > 10 || yangle > 10) continue;if (xarea < 15 || yarea < 15) continue;if (fabs(xarea - yarea) < 20 && fabs(xangle - yangle) < 2&& fabs(xrate - yrate) < 0.1&&fabs(x.size.height - y.size.height) < 5&& fabs(x.size.width - y.size.width) < 5)ret.push_back({ x,y });}}//cout << ret.size() << endl;for (auto x : ret) { drawrect(raw, x.first); drawrect(raw, x.second);}for (auto x : ret) drawtarget(raw, x.first, x.second);return; }int main() {Mat hero = imread("hero.jpg");Mat temp = pretreat(hero);fixarmor(hero,temp);show(hero, "hero");waitKey(0);//system("pause");return 0; }然后按道理是可以將藍(lán)減紅改成紅減藍(lán)來識(shí)別紅色燈條的我沒試過,如果識(shí)別不了,可以評(píng)論私信找我擊劍
截中間圖好麻煩
不要問我為什么用綠色畫圖,我做題看不到綠色,所以我要多看看綠色
總結(jié)
以上是生活随笔為你收集整理的对一张静态图片的识别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UVA - 10106 Product
- 下一篇: oracle表分区设计_论oracle分