uj5u.com熱心網友回復:
這里有一個想法:
- 加載影像,轉換為灰度,和大津的閾值為二進制影像 找到輪廓,用白色填充。
- 現在我們有了一個二進制影像,我們可以進行形態學操作。根據你要提取的物件,我們可以創建不同的結構核。對于矩形,我們可以使用
cv2.MORPH_RECT,對于橢圓,我們可以用更大的內核尺寸去除水平部分,并使用cv2.MORPH_ELLIPSE。 - 然后我們對剩余的輪廓進行過濾,為矩形和橢圓找到一個旋轉的邊界框 。
以下是該程序的可視化圖示
對于橢圓
來說
由于你沒有指定語言,這里有一個用Python實作的方法
。import cv2
import numpy as np
# 加載影像,轉換為灰度,大津的閾值為二進制影像
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(grey, 0, 255, cv2.THRESH_BINARY_INV cv2.THRESH_OTSU)[1] 。
# 尋找等高線,用白色填充等高線
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1] 。
for c in cnts:
cv2.drawContours(thresh, [c], 0, 255, -1)
# 矩形 ----------------------------------------
# 變形開放到獨立的矩形輪廓
rectangular_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20, 20))
rect = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, rectangular_kernel, iterations=4)
# 找到等高線并將旋轉的矩形畫到影像上
cnts = cv2.findContours(rect, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1] 。
isolated_rect = cv2.minAreaRect(cnts[0])
box = np.int0(cv2.boxPoints(isolated_rect))
cv2.drawContours(image, [box], 0, (36,255,12), 3)
# 矩形 ----------------------------------------
# 橢圓 ----------------------------------------
# 變形開放到獨立的橢圓輪廓
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,10))
ellipse = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2)
# 尋找橢圓的輪廓并進行過濾
cnts = cv2.findContours(ellipse, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1] 。
# 使用等高線面積進行過濾,也可以使用縱橫比或等高線的近似值
for c in cnts:
area = cv2.contourArea(c)
如果 area > 20000:
cv2.drawContours(image, [c], 0, (136,15,212), 3)
# 橢圓 ----------------------------------------
# 顯示
cv2.imshow('image', image)
cv2.imshow('thresh', thresh)
cv2.imshow('rect', rect)
cv2.imshow('ellipse', ellipse)
cv2.waitKey()
uj5u.com熱心網友回復:
使用點對的梯度衰減(最小化距離),你可以得到一個數字的最小切割串列。 將這些最小切割應用于原始物件,可以將其分割成獨立的物件。 你需要設定的唯一引數是minObjectRadius,它指定了你所關心的形狀的最小半徑(它被用來確定min cut的限制和最終形狀過濾)。
額外的處理影像。
代碼:
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <Windows.h>
#include <string>
using namespace std;
使用名稱空間cv.com
向量<元組<int, int>> generatePointPairs(int totalIndicies, int stride = 1)
{
vector<tuple<int, int>> pointPairs。
for (int i = 0; i < totalIndicies; i =stride)
{
for (int ii = 0; ii < totalIndicies; ii =stride)
{
tuple<int, int> pair(i, ii);
pointPairs.push_back(pair)。
}
}
回傳pointPairs。
}
double distSq(Point p1, Point p2)
{
return pow(p1.x - p2.x, 2) pow(p1.y - p2.y,2) 。
}
tuple<int, int> gradDecentPair(vector<Point> contour, tuple<int, int> pair)
{
int index0 = get<0>(pair)。
int index1 = get<1>(pair);
bool flip = false。
double lastDist = distSq(contour[get<0>(pair)], contour[get<1>(pair)])。
int flipCounter = 0。
while (true)
{
bool improvementFound = false。
int staticIndex = index1;
如果(翻轉){ staticIndex = index0; }
double bestDist = -1;
int bestIndex = -1;
for (int i = -5; i <= 5; i =1)
{
if (i == 0) { 繼續; }
int testIndex = index0 i;
如果(翻轉) { testIndex = index1 i; }
如果(testIndex < 0)
{ testIndex = contour.size(); }
否則,如果(testIndex >= contour.size())
{ testIndex -= contour.size(); }
double testDist = distSq(contour[staticIndex], contour[testIndex]) 。
如果(bestDist == -1 || testDist < bestDist)
{
bestIndex = testIndex;
bestDist = testDist。
}
}
如果(bestDist < lastDist)
{
如果(翻轉) { index1 = bestIndex; }
否則 { index0 = bestIndex; }
lastDist = bestDist;
improvementFound = true。
}
如果(index0 == index1) { break; }
如果(發現改進) { 繼續; }
否則
{
flipCounter ;
flip = !flip;
如果(flipCounter > 10) { break; } //非常肯定這可以做得更好,但現在很懶。
}
}
回傳 tuple<int, int> (index0, index1);
}
int main(int argc, char** argv)
{
int minObjectRadius = 75;
std::string fileName = "C:/Local Software/voyDICOM/resources/images/ShapeBlob.JPG" 。
Mat original = imread(fileName, cv::IMREAD_GRAYSCALE);
imshow("Original", original)。
Mat bwImg;
cv::threshold(original, bwImg, 0, 255, cv::THRESH_OTSU)。
bitwise_not(bwImg, bwImg)。
vector<vector<Point> > contours;
findContours(bwImg, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE)。
Mat minCuts(original.cols, original.rows, CV_8UC3)。
fillPoly(minCuts, contours, Scalar(255,0,0))。
向量<點>切割。
for (int i = 0; i < contours.size(); i )
{
std::cout << contours[i].size() << std::endl;
向量<元組<int, int>> pointPairs = generatePointPairs(contours[i].size(), 25);
for (int ii = 0; ii < pointPairs.size(); ii )
{
tuple<int, int> minCut = gradDecentPair(contours[i], pointPairs[ii])。
點p1 = contours[i][get<0>(minCut)]。
點p2 = contours[i][get<1>(minCut)]。
double tempDist = distSq(p1, p2);
如果(tempDist > 0 && tempDist <= pow(minObjectRadius, 2))
{
line(minCuts, contours[i][get<0>(minCut)], contours[i][get<1>(minCut)], Scalar(0, 0, 255)) 。
cuts.push_back(p1);
cuts.push_back(p2);
}
}
std::cout << i << " , " << contours.size() << std::endl;
}
imshow("minCuts", minCuts)。
fillPoly(bwImg, contours, 255)。
for (int i = 0; i < cuts.size(); i = 2)
{
line(bwImg, cuts[i],cuts[i 1], 0,2)。
}
imshow("cutPolys", bwImg)。
Mat finalShapes = imread(fileName, cv::IMREAD_COLOR);
int colorIndex = 0;
vector<Scalar> colors = { Scalar(255,0,0),Scalar(0,0,255),Scalar(0,0,0) };
vector<vector<Point> > contoursFinal;
findContours(bwImg, contoursFinal, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE) 。
for (int i = 0; i < contoursFinal.size(); i )
{
double tempArea = contourArea(contoursFinal[i]);
如果(tempArea < pow(minObjectRadius, 2)) { 繼續; }
vector<vector<Point>> singleContour;
singleContour.push_back(contoursFinal[i])。
fillPoly(finalShapes, singleContour, colors[colorIndex])。
colorIndex ;
如果(colorIndex >= colors.size()) { colorIndex = 0; }
}
imshow("finalPolys", finalShapes)。
waitKey(0);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/331081.html
標籤:


