0-1 행렬이 주어지면 연결된 도메인 프로그램의 반복에 대한 이해를 구하십시오.

연결된 domain_xunan003의 블로그-CSDN blog_connected 도메인을 찾기 위해 0-1 행렬이 주어짐

0-1 행렬 연결 도메인 찾기에 대한 이 기사의 방법은 비교적 상세하지만 C++를 배운 적이 없고 프로그래밍 경험이 거의 없기 때문에 이 블로그 게시물에서 제공되는 프로그램은 그다지 이해하기 어렵습니다.Tian은 마침내 몇 가지 단서를 얻었습니다. 여기에 요약을 작성하여 Xiaobai와 공유하겠습니다.여러분에게도 도움이 되었으면 합니다.

연결된 도메인을 찾는 방법은 세 단계로 나뉩니다.

첫 번째 단계: (냉장고 열기) 2차원 행렬의 경우 먼저 흰색 클리크의 각 행의 시작 및 끝 좌표(열)를 찾고 각 클리크에 레이블 시퀀스를 지정합니다.

2단계: 가까운 파벌의 레이블 병합 가까운 파벌을 식별하는 방법은 궤적(컬럼)의 중첩을 통해 궤적을 중첩하고 레이블을 귀화합니다. 두 종류의 클리크가 동등하다는 것(초기 선별 단계에서 두 가지 경우를 기준으로 사용), 균일한 격리가 필요합니다.

3단계: 동등한 그룹을 요약 및 스크리닝하고 모든 중복 그룹을 하나의 범주로 분류하여 서로 다른 감염 그룹으로 나눕니다.

위의 세 단계에 각각 해당하는 세 가지 절차가 제공됩니다.

void fillRunVectors(const Mat& bwImage, int& NumberOfRuns, vector<int>& stRun, vector<int>& enRun, vector<int>& rowRun)

void firstPass(vector<int>& stRun, vector<int>& enRun, vector<int>& rowRun, int NumberOfRuns,
    vector<int>& runLabels, vector<pair<int, int>>& equivalences, int offset)

void replaceSameLabel(vector<int>& runLabels, vector<pair<int, int>>&
    equivalence)

프로그램 단계 읽기

첫 번째 절차

1. 프로그램의 목적과 구현을 이해합니다.

각 프로그램을 받을 때 프로그램이 무엇을 하고 어떻게 구현되는지 완전히 이해해야 합니다.구현 방법에 대한 자세한 설명이 없으면 추측하고 확인해야 합니다. 단어를 모르는 기사처럼 이해할 수 없는 독해력.

첫 번째 프로그램은 흰색 clique의 각 행의 시작 및 끝 좌표를 완성하고 각 clique에 일련의 표시를 제공합니다.

1. 좌표 표시 방법

i번째 행의 j1번째 지점은 흰색 얼룩의 시작 좌표이고 j2 지점은 종료 좌표이므로 j1은 시작 대기열에, j2는 종료 대기열에 푸시되어야 하며 그에 따라 속합니다. i번째 행으로.

2. 시작 좌표와 종료 좌표 구분 방법

시작점(1, 첫 번째 열은 흰색 픽셀, 2, 이 열은 흰색 픽셀, 왼쪽 열은 검은색 픽셀)

종료 지점(1, 이 열은 흰색 픽셀, 오른쪽 열은 검은색 픽셀, 2, 마지막 열은 흰색 픽셀)

2. 프로그램의 대소 구조에 해당하는 기능 이해(대소 구조)

본체에 두 개의 for 루프가 있는데 각 for 루프 루프는 무엇입니까?

i는 행을 순환하고 j는 열을 순환하며 시작점과 끝점의 좌표를 찾습니다.

조건문(괄호 안의 내용 참조)의 판단은? 선택 후에 실현되는 기능은 무엇입니까(중괄호 끝에 있는 결론 참조)?

흰색 픽셀인지 확인하고 좌표 값을 각각 누릅니다.

3. 변수의 동작에 따라 각 변수의 참조 및 의미는 대상 함수에 해당하는 것으로 추측할 수 있습니다.

NumberofRuns는 흰색 그룹의 수를 나타내고 rowrun은 각 흰색 그룹이 속한 행 수에 해당합니다.

strun은 각 흰색 그룹의 시작 좌표를 나타내고 enrun은 각 흰색 그룹의 끝 좌표를 나타냅니다.

넷째, 최종 종합심사 절차

void fillRunVectors(const Mat& bwImage, int& NumberOfRuns, vector<int>& stRun, vector<int>& enRun, vector<int>& rowRun)
{
    for (int i = 0; i < bwImage.rows; i++)
    {
        const uchar* rowData = bwImage.ptr<uchar>(i);

        if (rowData[0] == 255)
        {
            NumberOfRuns++;
            stRun.push_back(0);
            rowRun.push_back(i);
        }
        for (int j = 1; j < bwImage.cols; j++)
        {
            if (rowData[j - 1] == 0 && rowData[j] == 255)
            {
                NumberOfRuns++;
                stRun.push_back(j);
                rowRun.push_back(i);
            }
            else if (rowData[j - 1] == 255 && rowData[j] == 0)
            {
                enRun.push_back(j - 1);
            }
        }
        if (rowData[bwImage.cols - 1])
        {
            enRun.push_back(bwImage.cols - 1);
        }
    }
}

두 번째 절차

여전히 위의 네 단계를 따르십시오.

1. firstPass 함수는 그룹 표시 및 등가 쌍 목록 생성을 완료합니다.

첫 번째 줄의 그룹에는 각각 레이블이 지정되어 있습니다.

b1.첫 번째 행을 제외한 모든 행의 파벌에 대해 이전 행의 모든 ​​파벌과 겹치는 영역이 없으면 새 레이블을 지정합니다.

b2. 이전 행의 클리크와 겹치는 영역만 있는 경우 이전 행의 클리크 레이블을 할당합니다.

b3.이전 행의 2개 이상의 클리크가 겹치는 영역이 있는 경우 연결된 클리크의 최소 레이블을 현재 클리크에 할당하고 이전 행의 이러한 클리크의 마크를 등가 쌍으로 작성하여 하나의 범주에 속함을 나타냅니다. (등가 쌍은 두 파벌 사이에 있음)

1. 인접한 행에 있는 두 군집이 겹치는 것을 어떻게 판단합니까?

두 연대의 시작과 끝의 일치로 판단하면 curstart>preend&curend<prestart

2. 여전히 두 개의 중첩 for 루프가 있습니다.

for 루프는 순회 기능을 구현하며 루프의 상한에 따라 루프의 개체를 프롬프트할 수 있습니다.

이 기능은 모든 그룹을 순회하고 각 그룹의 시작 및 끝 좌표를 읽어야 합니다.

이전 행의 모든 ​​클리크를 순회하여 이전 행의 각 클리크의 시작 및 끝 좌표를 읽어야 합니다.

중복 판단을 위한 두 정보 비교

첫 번째 조건문은 재귀 내용의 업데이트 및 교체를 구현합니다(이전 줄의 내용이 업데이트됨).

두 번째 조건문은 반복 판단을 구현하고 그룹에 레이블을 지정하여 등가 쌍을 생성합니다.

3. 각 변수의 의미를 대담하게 추측하고 신중하게 확인

strun 위임의 시작 좌표, enrun 종료 좌표, rowrun 위임에 해당하는 행 수 currowidx 현재 판단된 행 수, runlabels 위임 레이블 및 등가에 저장된 동등한 쌍

void firstPass(vector<int>& stRun, vector<int>& enRun, vector<int>& rowRun, int NumberOfRuns,
    vector<int>& runLabels, vector<pair<int, int>>& equivalences, int offset)
{
    runLabels.assign(NumberOfRuns, 0);
    int idxLabel = 1;
    int curRowIdx = 0;
    int firstRunOnCur = 0;
    int firstRunOnPre = 0;
    int lastRunOnPre = -1;
    for (int i = 0; i < NumberOfRuns; i++)
    {
        if (rowRun[i] != curRowIdx)
        {
            curRowIdx = rowRun[i];
            firstRunOnPre = firstRunOnCur;
            lastRunOnPre = i - 1;
            firstRunOnCur = i;

        }
        for (int j = firstRunOnPre; j <= lastRunOnPre; j++)
        {
            if (stRun[i] <= enRun[j] + offset && enRun[i] >= stRun[j] - offset && rowRun[i] == rowRun[j] + 1)
            {
                if (runLabels[i] == 0) // 没有被标号过
                    runLabels[i] = runLabels[j];
                else if (runLabels[i] != runLabels[j])// 已经被标号             
                    equivalences.push_back(make_pair(runLabels[i], runLabels[j])); // 保存等价对
            }
        }
        if (runLabels[i] == 0) // 没有与前一列的任何run重合
        {
            runLabels[i] = idxLabel++;
        }

    }
}

세 번째 절차

1. 등가 쌍을 처리하려면 여러 등가 시퀀스로 변환해야 합니다.

예를 들어 다음과 같은 등가 쌍이 있습니다.

(1,2),(1,6),(3,7),(9-3),(8,1),(8,10),(11,5),(11,8),(11 ,12),(11,13),(11,14),(15,11)

최종 시퀀스는 다음과 같습니다.

1-2-5-6-8-10-11-12-13-14-15

3-7-9

4

사용된 방법은 등가 시퀀스를 검색하기 위한 이미지 깊이 우선 순회 원칙입니다.

프로그램을 서두르지 말고 먼저 방법의 원리를 이해하십시오 . 그렇지 않으면 프로그램을 읽는 것이 매우 고통스러울 것입니다. 이미 시작된 것 같지만 실제로는 프로그램을 한 단어씩 읽을 수 없습니다. (영어 독해와 마찬가지로) 구조와 기능에 따라 프로그램을 읽어보세요.

이미지 깊이 우선 탐색 원리

모든 그룹 V의 등가(연결된) 그룹 W와 W에 상대적인 V의 다음 인접 점을 찾습니다.

참조:

그래프 순회: 깊이 우선 순회(DFS)_Uncertainty!!의 블로그-CSDN blog_깊이 우선 순회

둘째, 깊이 우선 순회 원칙에 따라 연결된 도메인을 찾는 과정에는 여러 중첩 순회 과정이 필요합니다.

먼저 모든 clique를 순회해야 합니다(행렬 열을 위에서 아래로). 특정 clique에 해당하는 clique를 순회해야 합니다(행렬 행을 왼쪽에서 오른쪽으로). 위에서 아래로 행렬 열)

i<maxlabel(그룹 번호), j<tempList(임시 등가 시퀀스), k<eqTab[].size()=maxLabel에 각각 해당

3. 각 변수의 의미 추측

maxLabel은 그래프의 수를 나타내고, eqTab은 등가 쌍 행렬을 나타내고, vecPairIt는 순환기를 나타내며, 그 기능은 전체 eqTab을 순회하는 것입니다.

labelFlag는 자신이 속한 클래스를 나타내고, tempList는 임시 클래스의 등가 시퀀스를 나타내고, equalList는 최종 등가 시퀀스를 나타냅니다.

void replaceSameLabel(vector<int>& runLabels, vector<pair<int, int>>&
    equivalence)
{
    int maxLabel = *max_element(runLabels.begin(), runLabels.end());
    vector<vector<bool>> eqTab(maxLabel, vector<bool>(maxLabel, false));
    vector<pair<int, int>>::iterator vecPairIt = equivalence.begin();
    while (vecPairIt != equivalence.end())
    {
        eqTab[vecPairIt->first - 1][vecPairIt->second - 1] = true;
        eqTab[vecPairIt->second - 1][vecPairIt->first - 1] = true;
        vecPairIt++;
    }
    vector<int> labelFlag(maxLabel, 0);
    vector<vector<int>> equaList;
    vector<int> tempList;
    cout << maxLabel << endl;
    for (int i = 1; i <= maxLabel; i++)
    {
        if (labelFlag[i - 1])
        {
            continue;
        }
        labelFlag[i - 1] = equaList.size() + 1;
        tempList.push_back(i);
        for (vector<int>::size_type j = 0; j < tempList.size(); j++)
        {
            for (vector<bool>::size_type k = 0; k != eqTab[tempList[j] - 1].size(); k++)
            {
                if (eqTab[tempList[j] - 1][k] && !labelFlag[k])
                {
                    tempList.push_back(k + 1);
                    labelFlag[k] = equaList.size() + 1;
                }
            }
        }
        equaList.push_back(tempList);
        tempList.clear();
    }
    cout << equaList.size() << endl;
    for (vector<int>::size_type i = 0; i != runLabels.size(); i++)
    {
        runLabels[i] = labelFlag[runLabels[i] - 1];
    }
}

추신: 프로그램 이해를 위한 약간의 문제 기록

1. if(a), a가 참이면 계속 진행합니다. 여기서 참은 0이 아닌 숫자와 문자를 포함합니다.

2. vector<bool>(maxLabel, false)  std :: 벡터 <bool> a(b,false); C#에서 찾기 -789(789zhao.com)

3. 반복자 vecPairIt  C++ 반복자 반복자 상세설명_C언어_스크립트하우스(jb51.net)

4. vecPairIt->  (1 메시지) -> C_Fan Hongkang의 블로그-CSDN 블로그에서 투석

5. eqTab[vecPairIt->first - 1][vecPairIt->second - 1] (1 메시지) C++에서 맵 컨테이너의 반복자 first second_imik의 블로그-CSDN blog_map의 first 및 second

6. Vector<vector<bool>>  벡터를 사용하여 2차원 벡터 구현 - Baidu Library(baidu.com)

7. "&&", "||" 및 "!". a && b, 하나의 거짓은 반드시 거짓이어야 하며, 연관성은 왼쪽에서 오른쪽으로. ||는 논리 연산자, a || b, 하나의 참은 반드시 참이어야 하고, 연관성은 왼쪽에서 오른쪽으로, &&! &&의 좌변이 성립하고 우변이 성립하지 않는 경우에만 성립한다.

 마지막으로 왜 그렇게 작은 프로그램이 그렇게 어렵게 느껴지나요, 5555, 이미지 알고리즘을 수행하는 데 적합한 지 의심하기 시작했습니다.

마지막으로 문제 해결 과정에 도움을 주셔서 감사합니다 제 답변이 도움이 되셨다면 엄지척 부탁드려요~~ 

추천

출처blog.csdn.net/MOZHOUH/article/details/125009011