WPF - XDL Tutorial

XDL MapView 활용 두번째

(piXoneer XDL Tutorial)

 

 

 

 

 2개의 NXMapView를 이용하여 Original View Processed View를 생성합니다.

 Original View에는 입력 영상을 도시하고

Processed View에는 공간 필터링된 영상을 도시하는 기능을 제작합니다.

 

 

2019. 04.

 

 

목차

XDL MapView 활용 두번째... 1

1    사용하기... 3

1.1    NXMapView 이용한 예제 프로그램 만들기... 3

1.2    메뉴 생성하기... 12

1.3    GridSplitter컨트롤 올리기... 13

1.4    NXMapView컨트롤 올리기... 14

1.5    영상 열기 기능... 16

1.6    Spatial Filter적용... 20

1.7    듀얼 뷰에 대한 동기화... 23

 

 

 

 

1     사용하기

본 튜터리얼을 공부하기 전에 먼저 XDL MapView 활용 첫번째를 먼저 선행하시기 바랍니다.

 

1.1    NXMapView를 이용한 예제 프로그램 만들기

1.1.1     Visual Studio 2015을 실행한다.

1.1.2     메뉴 [파일]-[새로 만들기]-[프로젝트]를 선택한다.

 

 

1.1.1     [새 프로젝트] 대화상자에서 왼쪽의 템플릿 창에서 “Visual C#”을 선택하고, 대화상자 중간의 목록에서 “WPF 응용 프로그램을 선택한다.

사용자가 원하는 경로를 선택한 다음 프로젝트 이름을 “XDL_MapView2” 으로 입력하고 [새 프로젝트] 대화상자의 확인버튼을 클릭한다. 이 문서에서는 대화상자 오른쪽 아래에 있는 “솔루션용 디렉터리 만들기”는 선택하지 않겠다. “확인” 버튼을 누르면 프로젝트가 기본적으로 생성되고, 화면에 Window을 디자인할 수 있는 화면이 뜬다. 만약 아래와 같은 Window 창이 생성되지 않으면, [솔루션 탐색기] 창에서 MainWindow.xaml”를 마우스 더블클릭을 하여 창을 연다.

 

 

1.1.2     솔루션 탐색기의 프로젝트 하부의 [참조]의 오른쪽 마우스 클릭을 통해 [참조추가]를 선택한다

 

 

1.1.3  [찾아보기]탭으로 이동한 후 “C:\Pixoneer\XDL1.2\bin\”경로로 이동한다. Ctrl키를   
 
누른 채 연속으로 “NXDL.dll, NXDLcc.dll, NXDLgr.dll, NXDLio.dll,
 
NXDLrs.dll, “NXMap.dll”을 선택한 후 “확인”버튼을 선택한다.

 

1.1.4  솔루션 탐색기의 프로젝트 하부의 [참조]항에 NXDL, NXDLcc, NXDLgr, NXDLio, NXDLrs, NXMap가 추가되었음을 확인한다.

1.1.5  MapView컨트롤을 활용하기 위해 MainWindow.xaml 창에서 namespace를 다음과 같이 추가한다.

 

1.2    메뉴 생성하기

1.2.1     MainWindow.xaml창에서 기본으로 생성된 Grid 레이아웃에 Grid.RowDefinition을 이용하여 두 개의 Row을 생성한다. Menu를 첫 번째 Cell에 배치하고 MenuItem 항목을 추가하고 아래의 표를 참고하여 [File]-[Open][Tool]-[SpatialFilter]을 생성한다. (메뉴 생성에 대한 자세한 설명은 XDL MapView1을 참고한다.)

 

 

Control Type

Header

Name

MenuItem

_File

 

MenuItem

_Open

openFileMenuItem

 

Control Type

Header

Name

MenuItem

_Tools

 

MenuItem

_Spatial Filter

spatialFilterToolsMenuItem

 

다음과 같은 XAML 코드가 생성되는 것을 확인할 수 있다.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

      <Menu Grid.Row="0">
        <MenuItem Header="_File" Margin="5,5,0,0">
        <MenuItem x:Name="openFileMenuItem" Header="_Open"/>
<MenuItem Header="_Tools" Margin="5,5,0,0">
<MenuItem x:Name="spatialFilterToolsMenuItem" Header="_Spatial Filter"> 
         </MenuItem>
      </Menu>
</Grid>

1.3    GridSplitter컨트롤 올리기

1.3.1     Grid 레이아웃 내부의 두 번째 Grid Row Cell에서 Grid.ColumnDefinition을 이용하여 세 개의 Column을 생성한다. 첫 번째 Cell(1)과 세 번째 Cell(3)MapView 컨트롤을 배치할 것이고 두 번째 Cell(2)GridSplitter을 배치할 것이다.

 

 

1.3.2     도구상자에서 GridSpliter을 끌어 (2)GridSplitter을 배치한다.

 

아래와 같은 XAML 코드가 생성되는 것을 확인할 수 있다.

<Grid Grid.Row="1">
       <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="*"/>
       </Grid.ColumnDefinitions>

<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch"/>
</Grid>

1.4    NXMapView컨트롤 추가하기

1.4.1     첫 번째 Column과 세 번째 Column MapView 컨트롤을 배치하기 위해 Window Forms Control을 사용한다. 이는 Window formsHosting 해주는 개체이다. (WindowFormIntegrationSystem.Window.Forms 을 어셈블리에 대한 참조 추가를 한다.)

1.4.2     Grid 레이아웃에 WindowFormsHost를 입력하고 앞서 namespace를 추가한 nxMap를 이용하여 NXMapView컨트롤을 불러와 배치한다(1), (3). NXMapView의 이름은 각각 nxMapView1nxMapView2으로 한다.  

NXMapView는 다양한 NXMapLayerXXXXX들을 담을수 있는 컨테이너이다. , NXMapView는 다양한 계층의 레이어로 구성하여 영상도시에 대한 다양한 기능을 구현이 가능하다.

<Grid Grid.Row="1">
       <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="*"/>
       </Grid.ColumnDefinitions>

<WindowsFormsHost Grid.Column="0" Margin="3,0,0,3">
            <nxMap:NXMapView x:Name="nxMapView1">
</nxMap:NXMapView>
</WindowsFormsHost>

<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch"/>

<WindowsFormsHost Grid.Column="2" Margin="3,0,3,3">
            <nxMap:NXMapView x:Name="nxMapView2">                  
            </nxMap:NXMapView>
</WindowsFormsHost>
</Grid>

 

.

1.4.3     NXMapView위에 NXMapLayerCompositesNXMapLayerGPU를 각각 추가한다.

NXMapLayerComposites XDMCompManager 객체에 있는 composite 목록을 도시한다. NXMapLayerGPU는 사용자가 OpenGL을 이용하여 객체를 도시할 수 있도록 하는 컨트롤을 나타낸다. 각각 이름은 nxMapLayerComposites1, nxMapLayerComposites2nxMapLayerGPU1, nxMapLayerGPU2로 한다.

 

<Grid Grid.Row="1">
       <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="*"/>
       </Grid.ColumnDefinitions>

<WindowsFormsHost Grid.Column="0" Margin="3,0,0,3">
            <nxMap:NXMapView x:Name="nxMapView1">
<nxMap:NXMapView.Controls>
             <nxMap:NXMapLayerComposites x:Name="nxMapLayerComposites1"/>
             <nxMap:NXMapLayerGPU x:Name="nxMapLayerGPU1" 
          </nxMap:NXMapView.Controls>
</nxMap:NXMapView>
</WindowsFormsHost>

<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch"/>

<WindowsFormsHost Grid.Column="2" Margin="3,0,3,3">
            <nxMap:NXMapView x:Name="nxMapView2">   
<nxMap:NXMapView.Controls>
            <nxMap:NXMapLayerComposites x:Name="nxMapLayerComposites2"/>
            <nxMap:NXMapLayerGPU x:Name="nxMapLayerGPU2"/>
         </nxMap:NXMapView.Controls>               
            </nxMap:NXMapView>
</WindowsFormsHost>
</Grid>

 

1.4.4     [F5]키를 눌러 프로그램을 실행한다. 아래와 같이 2개의 NXMapView컨트롤이 존재하는 지 확인한다.

 

 

1.5    영상 열기 기능

1.5.1     XAML창에서 [File]-[Open]을 더블 클릭하여 함수를 자동 생성한다.

 

 

private void openFileMenuItem_Click(object sender, RoutedEventArgs e)
{

}

 

1.5.2     향후 사용할 멤버 변수들을 선언한다.

public XRasterIO m_RasterIO;     // 영상의 입출력을 담당할 객체 선언
XRSLoadFile xrsFileInput1 = null;       // 영상 디스플레이용 파일 객체 생성
XRSLoadFile xrsFileInput2 = null;       // 영상 처리용 파일 객체 생성

double oldPixelSize = 0.0;      // 이전 화면의 픽셀 크기
double oldWCX = 0.0;            // 이전 화면의 화면 센터 X값
double oldWCY = 0.0;            // 이전 화면의 화면 센터 Y값

 

1.5.3     MainWindow생성자에 다음과 같이 객체를 생성한다. XRasterIO객체를 생성하고 NXMapLayerComposites 객체의 속성을 Visible할수 있도록 속성을 변경한다.

public MainWindow()
{
    InitializeComponent();

    String StrError;
    m_RasterIO = new XRasterIO();   // 객체 생성
    if (m_RasterIO.Initialize(out StrError) == false)   // 영상 입출력 객체 초기화
    {
        MessageBox.Show(StrError);
    }

    nxMapLayerComposites1.LayerVisible = true; // 영상레이어를 보이도록 속성을 변경
    nxMapLayerComposites2.LayerVisible = true; // 영상레이어를 보이도록 속성을 변경
}

 

1.5.4     [File]-[Open] 버튼을 눌렀을 때 생성될 [Open] 대화상자와 선택된 파일에 대한 XRSLoadFile객체를 생성하고 왼쪽 뷰 컨트롤에 도시를 수행한다.

private void openFileMenuItem_Click(object sender, RoutedEventArgs e)
{
// 1. 파일 Open을 수행한다.
     OpenFileDialog openFileDialog = new OpenFileDialog();
     openFileDialog.Filter = "XDM file(*.xdm)|*.XDM||";
     openFileDialog.RestoreDirectory = true;

     Nullable<bool> result = openFileDialog.ShowDialog();
     if (result != true) return;

     string strFilePath = openFileDialog.FileName;

     // 2. FileDriverManger를 통해 XRSLoadFile을 생성한다.
     string strError;
     xrsFileInput1 = m_RasterIO.LoadFile(strFilePath, out strError, false,
     eIOCreateXLDMode.All_NoMsg);
     xrsFileInput2 = m_RasterIO.LoadFile(strFilePath, out strError, false,
 eIOCreateXLDMode.All_NoMsg);

     if (xrsFileInput1 == null || xrsFileInput2 == null)
    {
          MessageBox.Show("Cannot Open"
          return;
     }

ShowImageOrigin();  // 실제 이미지를 왼쪽 화면에 도시하는 역할 

    // 새로운 파일을 열 때마다 오른쪽에 도시된 기존 이미지 파일을 삭제한다.
    // nxMapLayerComposites2개체에 존재하는 Composite를 관리하는 XDMCompManager를
// 꺼낸다. 
    XDMCompManager xdmCompManager = nxMapLayerComposites2.GetXDMCompManager();

    // 기존에 Composite가 존재한다면 모두 삭제한다.
    for (int i = 0; i < xdmCompManager.NumComp; i++)
    {
        XDMComposite comp = xdmCompManager.GetXDMCompositeAt(i);
        comp.Dispose();
    }
        xdmCompManager.RemoveXDMCompositeAll();
}

 

1.5.5     왼쪽 컨트롤에 이미지를 도시하는 ShowImageOrigin함수를 구현한다. 이 함수는 3개이상의 밴드를 포함하는 영상과 그 이하인 밴드를 포함하는 영상을 RGB 모드나 Gray모드로 도시하는 코드를 포함한다. 또한, 도시되는 영상에 대해 밝기를 향상시키기 위한 Image Enhancement 기능을 구현할 수 있다.

private void ShowImageOrigin()
{
     // 기존에 생성되어 있는 Composite가 있다면 Lock을 걸어 도시 수행을 잠시 멈춘다. 
     nxMapLayerComposites1.Lock();

    // nxMapLayerComposites1개체에 존재하는 XDMCompManager를 꺼낸다. 
// XDMCompManager가 실제로 Composite들의 관리를 수행한다.    
 XDMCompManager xdmCompManager = nxMapLayerComposites1.GetXDMCompManager();

    // 기존에 Composite가 존재한다면 모두 삭제한다.
    for (int i = 0; i < xdmCompManager.NumComp; i++)
    {
          XDMComposite comp = xdmCompManager.GetXDMCompositeAt(i);
          comp.Dispose();
    }
    xdmCompManager.RemoveXDMCompositeAll();

    // XDMComposite를 생성한다. .
    XDMComposite newComp = new XDMComposite();

    // 로딩된 파일로 부터 밴드의 갯수가 칼라로 그릴것인지 흑백으로 그릴것인지를 판단한다.
    // 만약 3개 미만인 경우는 Gray모드로 그리고, 3개 이상인 경우는 칼라로 그린다.
    int nNumBand = xrsFileInput1.NumBand;
    if (nNumBand < 3)   // 3개 미만의 밴드를 가지고 있는 경우
    {
          // Default로 0번째 밴드를 Gray모드로 그린다. 
          XDMBand band = xrsFileInput1.GetBandAt(0);

          // 밴드 이름을 그대로 Composite이름으로 설정
          newComp.Name = band.BandName;

          // Gray Mode로 그리는것을 설정
          newComp.Mode = eCompMode.Gray;

          // Composite의 0번에 Band설정, Gray모드에서는 0번 밴드만을 인식한다. 
          newComp.SetBand(ref band, 0);
          // 영상 Enhancement를 위해 Histogram의 범위 설정(정규분포 95% 영역)
          newComp.SetCutType(eCompCutType.Ct95, 0);
          // 영상 Enhancement를 위해 Histogram적용시 전체 영역에 대한
// Histogram(Band)설정, Visible은 현재 영역
          newComp.SetStretchCoverage(eCompStretchCoverage.Band, 0);
          // 영상 Enhancement를 위해 Histogram의 Stretch형태 설정(Gaussian으로 설정)
          newComp.SetStretchType(eCompStretchType.Gaussian, 0);
     }
     else // 3개 이상의 밴드를 가지고 있는 경우 
     {
          XDMBand band1 = xrsFileInput1.GetBandAt(0);
          XDMBand band2 = xrsFileInput1.GetBandAt(1);
          XDMBand band3 = xrsFileInput1.GetBandAt(2);
// 파일 이름을 Compoiste이름으로 설정

         newComp.Name = xrsFileInput1.FileName; 

         newComp.Mode = eCompMode.RGB;  // RGB Mode로 그리는것을 설정
newComp.SetBand(ref band1, 0); // Composite의 0번에 Band설정, 
Blue Channel설정 
newComp.SetBand(ref band2, 1); // Composite의 1번에 Band설정, 
Green Channel설정
         newComp.SetBand(ref band3, 2); // Composite의 2번에 Band설정, 
Red Channel설정

         for (int i = 0; i < 3; i++)
         {
            // 영상 Enhancement를 위해 Histogram의 범위 설정(정규분포 95% 영역)
            newComp.SetCutType(eCompCutType.Ct95, i);
            // 영상 Enhancement를 위해 Histogram적용시 전체 영역에 대한
// Histogram(Band)설정, Visible은 현재 영역
            newComp.SetStretchCoverage(eCompStretchCoverage.Band, i);
            // 영상 Enhancement를 위해 Histogram의 Stretch형태 설정(Gaussian으로 설정)
            newComp.SetStretchType(eCompStretchType.Gaussian, i);
         } 
}

       // 생성된 Composite를 XDMCompManger객체에 추가한다. 
       xdmCompManager.AddXDMComposite(ref newComp);

       // 전체 화면 보기를 설정한다.
       nxMapLayerComposites1.ZoomFit();

       // 화면 업데이트를 수행한다. 
       nxMapLayerComposites1.Invalidate();

       // 설정된 Lock를 해제한다. 
       nxMapLayerComposites1.UnLock();
}

 

1.6    Spatial Filter적용

1.6.1      XAML창에서 [Tool]-[Spatial Filter] 버튼을 더블 클릭하여 “Spatial Filter”기능 구현을 위한 함수를 자동 생성시킨다.

 

 

private void spatialFilterToolsMenuItem_Click(object sender, RoutedEventArgs e)
{

}

 

1.6.2     Open된 영상에 대한 공간 필터링 수행을 위한 코드를 작성한다.

private void spatialFilterToolsMenuItem_Click(object sender, RoutedEventArgs e)
{
      if (xrsFileInput2 == null) return;

      XBandParamSpatialFilter param = new XBandParamSpatialFilter();
      param.SrcBand = xrsFileInput2.GetBandAt(0); // 영상처리를 위한 Source Band를 설정
      param.FilterMethod = eSpatialFilterMethod.Average; // 필터 설정
      param.KernelSize = 3; // Filter의 커널 사이즈 설정

      // XDMBandSpatialFiter 밴드를 생성하고 입력 변수를 설정
      XDMBandSpatialFilter bandSF = new XDMBandSpatialFilter();
      bandSF.SetInputParam(ref param);

      ShowProcessedImage(bandSF);
}

 

1.6.3     ShowProcessedImage 코드를 작성한다. 여기에서는 DefaultGray로 그리는 코드를 입력하였다. 만약, 공간 필터링된 이미지를 RGB로 만들고 싶다면 ShowImageOrigin함수에서 구현하였던 것처럼 3개의 Band에 대해 각각 공간 필터링을 수행하고 NXLayerComposites객체의 모드를 RGB로 설정하여 도시하면 된다.

private void ShowProcessedImage(XDMBandSpatialFilter bandSF)
{
    // 기존에 생성되어 있는 Composite가 있다면 Lock을 걸어 도시 수행을 잠시 멈춘다. 
    nxMapLayerComposites2.Lock();

    // nxMapLayerComposites2개체에 존재하는 XDMCompManager를 꺼낸다. 
// XDMCompManager가 실제로 Composite들의 관리를 수행한다. 
    XDMCompManager xdmCompManager = nxMapLayerComposites2.GetXDMCompManager();

    // 기존에 Composite가 존재한다면 모두 삭제한다.
    for (int i = 0; i < xdmCompManager.NumComp; i++)
    {
        XDMComposite comp = xdmCompManager.GetXDMCompositeAt(i);
        comp.Dispose();
    }
    xdmCompManager.RemoveXDMCompositeAll();

    // XDMComposite를 생성한다. .
    XDMComposite newComp = new XDMComposite();

    // Spatial Filter 밴드를 Gray모드로 그린다. 
    XDMBand band = bandSF;

    // 밴드 이름을 그대로 Composite이름으로 설정
    newComp.Name = band.BandName;

    // Gray Mode로 그리는 것을 설정
    newComp.Mode = eCompMode.Gray;

    // Composite의 0번에 Band설정, Gray모드에서는 0번 밴드만을 인식한다. 
    newComp.SetBand(ref band, 0);
    // 영상 Enhancement를 위해 Histogram의 범위 설정(정규분포 95% 영역)
    newComp.SetCutType(eCompCutType.Ct95, 0);
    // 영상 Enhancement를 위해 실시간 영상처리는 반드시 Visible로 설정
    newComp.SetStretchCoverage(eCompStretchCoverage.Visible, 0);
    // 영상 Enhancement를 위해 Histogram의 Stretch형태 설정(Gaussian으로 설정)
    newComp.SetStretchType(eCompStretchType.Gaussian, 0);

    // 생성된 Composite를 XDMCompManger객체에 추가한다. 
    xdmCompManager.AddXDMComposite(ref newComp);

    // 전체 화면 보기를 설정한다.
    nxMapLayerComposites2.ZoomFit();

    // 화면 업데이트를 수행한다. 
    nxMapLayerComposites2.Invalidate();

    // 설정된 Lock를 해제한다. 
    nxMapLayerComposites2.UnLock();
}

 

1.7    듀얼 뷰에 대한 동기화

1.7.1     GPU Layer을 나타내는 nxMapLayerGPU1XAML코드로 이동하여 OnOrthoRender 이벤트를 추가한다. [속성]-[이벤트] 버튼을 누르고 OnOrthoRender를 더블 클릭하여 자동 생성 함수를 만든다.

 

 

1.7.2     [속성]-[이벤트]버튼을 누르고 OnOrthoRender를 더블 클릭하여 자동 생성 함수를 만든다.

private bool nxMapLayerGPU1_OnOrthoRender(NXMapLayerGPU sender, NXMapViewDrawArgs DrawArgs)
{

}

 

1.7.3     nxMapLayerGPU1_OnOrthoRender함수에 동기화 할 수 있는 코드를 작성한다.

private bool nxMapLayerGPU1_OnOrthoRender(NXMapLayerGPU sender, NXMapViewDrawArgs DrawArgs)
{
// 마우스가 왼쪽 NXMapView컨트롤 위에 존재하는지 여부 확인
      if (!this.nxMapView1.IsUnderMouse())
           return default(bool);

      // Screen Bound를 얻는다. 
      double x1w, x2w, y1w, y2w;
      x1w = x2w = y1w = y2w = 0.0;
      nxMapView1.GetScreenBound(ref x1w, ref x2w, ref y1w, ref y2w);

      // 화면의 중심점을 계산한다.
      double wcx, wcy;
      wcx = (x1w + x2w) / 2.0;
      wcy = (y1w + y2w) / 2.0;

      // 현재 화면의 화소 공간 크기를 얻는다.
      double pixelSize = DrawArgs.PixelSize;

      // 이전 화소의 크기/센터와 현재 화면의 화소의 크기/센터값이 모두 동일한 경우 
// 도시 성능을 위해 적용하지 않는다.
      if (oldPixelSize == DrawArgs.PixelSize &&
      oldWCX == wcx &&
      oldWCY == wcy) return true;

      // 왼쪽 NXMapView의 화면 도시 정보를 오른쪽 NXMapView컨트롤에 적용한다.
      nxMapView2.SetWorld(new XVertex2d(wcx, wcy), new XVertex2d(pixelSize,
 pixelSize), new XAngle(0));

      // 현재 픽셀 크기/화면 중심 좌표를 저장한다.
      oldPixelSize = DrawArgs.PixelSize;
      oldWCX = wcx;
      oldWCY = wcy;

      nxMapView2.RefreshScreen();

      return true;
}

 

1.7.4     [F5]키를 눌러 프로그램을 실행한다. 실행된 프로그램으로부터 [File]-[Open]버튼을 눌러 홈페이지에서 다운로드 받은 “etm.xdm”을 선택한다. [Tool]-[Spatial Filter]버튼을 눌러 공간 필터링 처리를 수행한다.

 

 

1.7.5     왼쪽 컨트롤에 마우스 커서를 올리고 마우스 휠을 당기거나 밀어준다. 또한 마우스 오른쪽 클릭을 수행한 채로 끌기를 수행해 오른쪽에 있는 영상이 동기화 되는지 확인한다.