/
LitvinovVN
/
ComputerVision
Обзор
Документация
Войти
/
LitvinovVN
/
ComputerVision
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
Klette_Computer_Vision_2019/part3/code/chapter3_image_analysis.cpp
286 строк
8 KB
Art_Lun
Ковалевский глава 3 Клетте
22 дек 2025, 00:45
22 дек 2025, 00:45
1cf5214
Код
Авторство
О чём код?
#include <iostream> #include <vector> #include <queue> #include <cmath> #include <limits> #include <map> using namespace std; using ImageBool = vector<vector<bool>>; using ImageInt = vector<vector<int>>; using ImageDouble = vector<vector<double>>; const vector<pair<int,int>> A4 = { {-1,0},{1,0},{0,-1},{0,1} }; const vector<pair<int,int>> A8 = { {-1,0},{1,0},{0,-1},{0,1}, {-1,-1},{-1,1},{1,-1},{1,1} }; constexpr double PI = 3.14159265358979323846; // ============================================================ // 3.1 Компоненты связности // ============================================================ vector<vector<pair<int,int>>> connectedComponents( const ImageBool& img, int connectivity) { int h = img.size(); int w = img[0].size(); vector<vector<bool>> visited(h, vector<bool>(w,false)); vector<vector<pair<int,int>>> components; const auto& neigh = (connectivity == 4) ? A4 : A8; for(int y=0;y<h;y++){ for(int x=0;x<w;x++){ if(img[y][x] && !visited[y][x]){ queue<pair<int,int>> q; vector<pair<int,int>> comp; q.push({y,x}); visited[y][x] = true; while(!q.empty()){ auto [cy,cx] = q.front(); q.pop(); comp.push_back({cy,cx}); for(auto [dy,dx]:neigh){ int ny = cy + dy; int nx = cx + dx; if(ny>=0 && ny<h && nx>=0 && nx<w){ if(img[ny][nx] && !visited[ny][nx]){ visited[ny][nx] = true; q.push({ny,nx}); } } } } components.push_back(comp); } } } return components; } // ============================================================ // 3.1 Трассировка границы (упрощённый Восс) // ============================================================ vector<pair<int,int>> traceBoundary(const ImageBool& img) { int h = img.size(); int w = img[0].size(); pair<int,int> start{-1,-1}; for(int y=0;y<h;y++){ for(int x=0;x<w;x++){ if(img[y][x]){ start = {y,x}; break; } } if(start.first!=-1) break; } vector<pair<int,int>> boundary; boundary.push_back(start); pair<int,int> prev{-1,-1}; pair<int,int> curr = start; while(true){ bool found = false; pair<int,int> next; for(auto [dy,dx]:A8){ int ny = curr.first + dy; int nx = curr.second + dx; if(ny>=0 && ny<h && nx>=0 && nx<w){ if(img[ny][nx] && make_pair(ny,nx)!=prev){ next = {ny,nx}; found = true; break; } } } if(!found || next == start) break; boundary.push_back(next); prev = curr; curr = next; } return boundary; } // ============================================================ // 3.2 Геометрия // ============================================================ int area(const ImageBool& img) { int s = 0; for(auto& row:img) for(bool v:row) if(v) s++; return s; } double perimeter(const vector<pair<int,int>>& boundary) { double L = 0.0; for(size_t i=1;i<boundary.size();i++){ int dy = abs(boundary[i].first - boundary[i-1].first); int dx = abs(boundary[i].second - boundary[i-1].second); if(dy+dx==1) L += 1.0; else L += sqrt(2.0); } return L; } vector<double> curvature(const vector<pair<int,int>>& c, int k=3) { vector<double> curv; int n = c.size(); for(int i=k;i<n-k;i++){ double x0=c[i].second, y0=c[i].first; double x1=c[i-k].second, y1=c[i-k].first; double x2=c[i+k].second, y2=c[i+k].first; double a = x1 - 2*x0 + x2; double b = y1 - 2*y0 + y2; double c1 = x2 - x1; double d1 = y2 - y1; double denom = pow(c1*c1 + d1*d1,1.5); if(denom==0) curv.push_back(0); else curv.push_back(2*(a*d1 - b*c1)/denom); } return curv; } ImageDouble distanceTransform(const ImageBool& img) { int h = img.size(); int w = img[0].size(); ImageDouble D(h, vector<double>(w, numeric_limits<double>::infinity())); vector<pair<int,int>> zeros, ones; for(int y=0;y<h;y++) for(int x=0;x<w;x++) (img[y][x] ? ones : zeros).push_back({y,x}); for(auto [y,x]:ones){ for(auto [zy,zx]:zeros){ double d = (y-zy)*(y-zy) + (x-zx)*(x-zx); D[y][x] = min(D[y][x], d); } D[y][x] = sqrt(D[y][x]); } return D; } // ============================================================ // 3.3 Анализ значений изображения // ============================================================ vector<int> histogram(const ImageInt& img, int levels=256) { vector<int> hist(levels,0); for(auto& row:img) for(int v:row) hist[v]++; return hist; } void imageStatistics(const ImageInt& img) { double sum=0, sq=0; int mn=255, mx=0; int n=0; for(auto& r:img) for(int v:r){ sum+=v; sq+=v*v; mn=min(mn,v); mx=max(mx,v); n++; } double mean = sum/n; double var = sq/n - mean*mean; cout<<"Min="<<mn<<" Max="<<mx <<" Mean="<<mean<<" Var="<<var<<endl; } // ============================================================ // 3.4 Поиск прямых (Хаф) // ============================================================ vector<vector<int>> houghLines(const ImageBool& edges, int thetaSteps=180) { int h=edges.size(), w=edges[0].size(); int diag = sqrt(h*h + w*w); vector<vector<int>> acc(2*diag, vector<int>(thetaSteps,0)); for(int y=0;y<h;y++) for(int x=0;x<w;x++) if(edges[y][x]) for(int t=0;t<thetaSteps;t++){ double theta = PI * t / thetaSteps; int rho = round(x*cos(theta) + y*sin(theta)) + diag; if(rho>=0 && rho<2*diag) acc[rho][t]++; } return acc; } // ============================================================ // Пример использования // ============================================================ int main() { int H=50, W=50; ImageInt img(H, vector<int>(W,0)); for(int y=10;y<40;y++) for(int x=20;x<30;x++) img[y][x]=200; ImageBool binary(H, vector<bool>(W,false)); for(int y=0;y<H;y++) for(int x=0;x<W;x++) binary[y][x]=img[y][x]>0; auto comps = connectedComponents(binary,8); auto boundary = traceBoundary(binary); cout<<"Components: "<<comps.size()<<endl; cout<<"Area: "<<area(binary)<<endl; cout<<"Perimeter: "<<perimeter(boundary)<<endl; auto curv = curvature(boundary); if(!curv.empty()) cout<<"Curvature sample: "<<curv[0]<<endl; auto D = distanceTransform(binary); cout<<"DT center: "<<D[25][25]<<endl; imageStatistics(img); auto acc = houghLines(binary); cout<<"Hough max: "<<acc[0][0]<<endl; return 0; }