Opencv 연결 영역 중심 인 스 턴 스 구하 기

우 리 는 때때로 어떤 물체 의 중심 을 구 해 야 한다.여 기 는 일반적으로 이미 지 를 이치 화하 여 이 물체 의 윤곽 을 얻어 낸 다음 에 그 레이스 케 일 중심 법 에 따라 모든 물체 의 중심 을 계산한다.
절 차 는 다음 과 같다.
1)적합 한 한도 값 이치 화
2)윤곽 구하 기
3)계산 중심
otsu 알고리즘 최 적 한도 값 구하 기
otsu 법(최대 클래스 간 분산 법,때로는 대진 알고리즘 이 라 고도 함)은 집합 사상 을 사용 하여 이미지 의 그 레이스 케 일 수 를 그 레이스 케 일 등급 에 따라 2 개 부분 으로 나 누 어 두 부분 간 의 그 레이스 케 일 차이 가 가장 크 고 각 부분 간 의 그 레이스 케 일 차이 가 가장 적 으 며 분산 계산 을 통 해 적당 한 그 레이스 케 일 등급 을 찾 아 구분 합 니 다.otsu 알고리즘 은 이미지 분할 에서 한도 값 을 선택 하 는 가장 좋 은 알고리즘 으로 계산 이 간단 하고 이미지 밝기 와 대비 도의 영향 을 받 지 않 습 니 다.따라서 클래스 간 의 방 차 가 가장 큰 분할 은 오 분 확률 이 가장 적 다 는 것 을 의미한다.
계산 윤곽
opencv 에서 함수 findContours 함수
findContours(이치 화 이미지,윤곽,hierarchy,윤곽 검색 모드,윤곽 유사 방법,offset)
그 레이스 케 일 중심 법
그 레이스 케 일 중심 법 으로 중심 을 계산 하고 그 레이스 케 일 중심 법 은 지역 내 모든 픽 셀 위치 에 있 는 그 레이스 케 일 값 을 이 점 의'질량'으로 하 며 지역 중심 을 구 하 는 공식 은 다음 과 같다.

그 중에서 f(u,v)는 좌표 가(u,v)인 픽 셀 점 의 그 레이스 케 일 값 으로 목표 구역 의 집합 이 고 지역 중심 좌표 이 며 그 레이스 케 일 중심 법 은 지역 의 에너지 중심 을 추출 합 니 다.

//otsu      
int Otsu(Mat &image)
{
  int width = image.cols;
  int height = image.rows;
  int x = 0, y = 0;
  int pixelCount[256];
  float pixelPro[256];
  int i, j, pixelSum = width * height, threshold = 0;

  uchar* data = (uchar*)image.data;

  //    
  for (i = 0; i < 256; i++)
  {
    pixelCount[i] = 0;
    pixelPro[i] = 0;
  }

  //                    
  for (i = y; i < height; i++)
  {
    for (j = x; j<width; j++)
    {
      pixelCount[data[i * image.step + j]]++;
    }
  }


  //                
  for (i = 0; i < 256; i++)
  {
    pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
  }

  //  ostu  ,           
  //     [0,255],           ,      
  float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
  for (i = 0; i < 256; i++)
  {
    w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

    for (j = 0; j < 256; j++)
    {
      if (j <= i) //     
      {
        // i     ,        
        w0 += pixelPro[j];
        u0tmp += j * pixelPro[j];
      }
      else    //     
      {
        // i     ,        
        w1 += pixelPro[j];
        u1tmp += j * pixelPro[j];
      }
    }

    u0 = u0tmp / w0;    //         
    u1 = u1tmp / w1;    //         
    u = u0tmp + u1tmp;   //          
                //       
    deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
    //                
    if (deltaTmp > deltaMax)
    {
      deltaMax = deltaTmp;
      threshold = i;
    }
  }
  //      ; 
  return threshold;
}

int main()
{
  Mat White=imread("white.tif");//    
  int threshold_white = otsu(White);//    ,  otsu
  cout << "    :" << threshold_white << endl;
  Mat thresholded = Mat::zeros(White.size(), White.type());
  threshold(White, thresholded, threshold_white, 255, CV_THRESH_BINARY);//   
  vector<vector<Point>>contours;
  vector<Vec4i>hierarchy;
  findContours(thresholded, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);//    

  int i = 0;
  int count = 0;
  Point pt[10];//         
  Moments moment;// 
  vector<Point>Center;//            
  for (; i >= 0; i = hierarchy[i][0])//           
  {
    Mat temp(contours.at(i));
    Scalar color(0, 0, 255);
    moment = moments(temp, false);
    if (moment.m00 != 0)//     0
    {
      pt[i].x = cvRound(moment.m10 / moment.m00);//       
      pt[i].y = cvRound(moment.m01 / moment.m00);//       

    }
      Point p = Point(pt[i].x, pt[i].y);//    
      circle(White, p, 1, color, 1, 8);//        
      count++;//            
      Center.push_back(p);//        Center   
    }
  }
  cout << "     :" << Center.size() << endl;
  cout << "    :" << contours.size() << endl;
  imwrite("Center.tif", White);
}
원본 그림:

이치 화:

중심 점:

보충 지식:opencv 템 플 릿 패키지 에 따라 한도 값 화 된 윤곽 조합
이미지 처리 에서 특징 과 배경의 대비 도가 높 아야 하 는 동시에 적당 한 이미지 분할 도 문 제 를 해결 하 는 관건 이다.
블 로 거들 의 이전 방법 은 기본 적 인 것 이 특징 이 고 반드시 가장 큰 연결 역 이 어야 하기 때문에 한도 값 화 된 후에 윤곽 을 찾 아 면적 이 가장 큰 윤곽 을 직접 추출 하면 된다.
그러나 다른 상황 이 존재 할 수 있 습 니 다.아무리 한도 값 화 와 팽창 이 있어 도 원 하 는 특징 은 여러 조각 으로 나 뉘 어 져 있 습 니 다.즉,끊 어 집 니 다.이때 예측 할 수 없 는 간섭 과 소음 을 더 하면 findcontours 이후 많은 윤곽 을 얻 을 수 있 습 니 다.
그러면 문제 가 생 겼 습 니 다.우리 가 필요 로 하 는 것 은 어떤 윤곽 입 니까?아니면 몇 개의 윤곽 이 조 합 된 구역 입 니까?
본문의 의미 도 여기에 있다.
템 플 릿 의 볼록 가방 에 따라 그림 에서 가장 비슷 한 윤곽 조합 을 구 합 니 다.
이 방법 은 주로 matchspes 함 수 를 사용 하고 이러한 전 제 를 바탕 으로 한다.템 플 릿 패키지 의 2/3 부분 은 템 플 릿 패키지 와 의 싱크로 율 이 템 플 릿 패키지 의 1/2 부분 보다 크다.
말 이 많 지 않 으 니 코드 를 달 아 라.

void getAlikeContours(std::vector<cv::Point> Inputlist, cv::Mat InputImage, std::vector<cv::Point> &Outputlist)
{
 Mat image;
 InputImage.copyTo(image);
 vector<vector<Point> > contours;
 findContours(image, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);//       
 for (int idx = contours.size() - 1; idx >= 0; idx--)
  {
	for (int i = contours[idx].size() - 1; i >= 0; i--)
	{
		if (contours[idx][i].x == 1 || contours[idx][i].y == 1 || contours[idx][i].x == image.cols - 2 || contours[idx][i].y == image.rows - 2)
		{
			swap(contours[idx][i], contours[idx][contours[idx].size() - 1]);
			contours[idx].pop_back();
			
		}
	}
	//         ,     
	for (int idx = contours.size() - 1; idx >= 0; idx--)
	{
		if (contours[idx].size() == 0) contours.erase(contours.begin() + idx);
	}
 
	while (true)
	{
		if (contours.size() == 0) break;
		if (contours.size() == 1)
		{
			vector<Point> finalList;
			finalList.assign(contours[0].begin(), contours[0].end());
			convexHull(Mat(finalList), Outputlist, true);
			break;
		}
 
		int maxContourIdx = 0;
		int maxContourPtNum = 0;
		for (int index = contours.size() - 1; index >= 0; index--)
		{
			if (contours[index].size() > maxContourPtNum)
			{
				maxContourPtNum = contours[index].size();
				maxContourIdx = index;
			}
		}
		//     
		int secondContourIdx = 0;
		int secondContourPtNum = 0;
		for (int index = contours.size() - 1; index >= 0; index--)
		{
			if (index == maxContourIdx) continue;
			if (contours[index].size() > secondContourPtNum)
			{
				secondContourPtNum = contours[index].size();
				secondContourIdx = index;
			}
		}
		vector<Point> maxlist;
		vector<Point> maxAndseclist;
		vector<Point> maxlistHull;
		vector<Point> maxAndseclistHull;
		maxlist.insert(maxlist.end(), contours[maxContourIdx].begin(), contours[maxContourIdx].end());
		maxAndseclist.insert(maxAndseclist.end(), contours[maxContourIdx].begin(), contours[maxContourIdx].end());
		maxAndseclist.insert(maxAndseclist.end(), contours[secondContourIdx].begin(), contours[secondContourIdx].end());
		convexHull(Mat(maxlist), maxlistHull, true);
		convexHull(Mat(maxAndseclist), maxAndseclistHull, true);
		double maxcontourScore = matchShapes(Inputlist, maxlistHull, CV_CONTOURS_MATCH_I1, 0);
		double maxandseccontourScore = matchShapes(Inputlist, maxAndseclistHull, CV_CONTOURS_MATCH_I1, 0);
		if (maxcontourScore>maxandseccontourScore)
		{
			contours[maxContourIdx].insert(contours[maxContourIdx].end(), contours[secondContourIdx].begin(), contours[secondContourIdx].end());
		}
		contours.erase(contours.begin() + secondContourIdx);
	}
}
이상 의 Opencv 에서 연결 구역 의 중심 인 스 턴 스 를 구 하 는 것 은 바로 편집장 이 여러분 에 게 공유 하 는 모든 내용 입 니 다.여러분 께 참고 가 되 고 여러분 들 이 저 희 를 많이 지지 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기