본문 바로가기

C# 윈도우 프로그래밍

c# tensorflow object detection(1)

 

이번장에서는 obdetection 알고리즘을 텐서플로우를 이용한 c# 으로 구현해보도록 한다.

테스트 환경은 텐서플로우 1.15버전으로 래핑된 텐서플로우 .net 버젼을 이용할 것이다. Scisharp프로젝트로

nuget패키지에서 tensorflow.net을 검색하면 나온다.

 

단점으로는 파이썬 으로 구현했을때보다 1.3배정도 느리다. 이번에 텐서플로우 2.x 버젼이 나오면서 빨라지긴했는데 아직 테스트가 필요하긴 하다.

 

간략하게 텐서플로우에 대해 설명하자면,

 

텐서플로우란?

 

2015년 11월9일 아파치 2.0 오픈소스 라이선스로 공개된 머싱러닝을 위한 End to End 플랫폼으로 도구, 라이브러리,커뮤니티 리소스로 구성된 포괄적이고 유연한 생태계를 통해 머싱러닝이 점목된 애플리케이션을 손쉽게 빌드 및 배포할수있게 되어있다.

 

사실 이 텐서플로우는 구글 브레인팀에서 두번째로 공개된 오픈소스로서 처음에는 디스트빌리프(DistBelief)라고 2011년에 먼저 먼저 만든 머싱러닝 소스가 있었다. 이 디스트빌리프에 원래 구글에서 검색, 음성검색, 광고, 구글 포토, 구글 맵스, 스트리트뷰, 번역 , 유튜브 등 실제 서비스에 적용되고 있었는데 현재는 이 딥러닝 인공 신경망들이 거의다 텐서플로우로 이전된 상태이다.

 

예전 1.x 버젼때의 텐서플로우는 페이스북의 파이토치보다 gpu연산을 했을때 상대적으로 느린단점이 있었는데

 

그것도 2.x때는 거의 비등비등해져서 우월을 가리기가 힘들다. 특히 2.x 버젼때는 케라스라는 하이레벨 API를 정식 채택해서 중구난방 하던 API를 통일하는식으로 매우 편리하게 사용할수 있게 하였습니다.

 

텐서플로우(Tensorflow)는 데이터 플로우 그래프(Data Flow graph)를 사용해서 수치연산을 하는 라이브러리로서, 그래프의 노드(node)는 수치 연산을 나타내고, 엣지(edge)는 노드 사이를 이동하는 다차원 데이터배열(Tensor)를 나타냅니다. 유연한 아키텍처로 구성되어있어 코드 수정없이 데스크탑,서버,모바일 디바이스 상관없이 CPU나 GPU를 사용해서 연산을 구동할수 있습니다. 

 

원래 머싱러닝과 딥 러닝 뉴럴 네트워크 목적으로 설계되었긴하나 여러 다른 분야에도 충분히 적용될 수 있다는 장점이 있습니다.

C#으로 구현하기

우선 c#에서 바로 사용하기 위해서 래핑 라이브러리인 tensorflow.net 을 사용 할 것입니다. tensorflow.net 은 시카고에 있는 Scisharp stack팀에서 진행하고 오픈소스 라이브러리로 텐서플로우를 c#으로 래핑하고 있는데

정식버젼을 1.15까지고 현재 테스트로 2.3버젼을 진행하고 있습니다. 

이번장에서는 정식버젼으로만 동작을 할것이고 차후 2.x 버젼대를 사용해서 구현할것입니다.

 

현재 테스트에서는 파이썬버젼보다 2.x대에서 CPU연산일때 더 빠르다고는 하는데 GPU/TPU는 테스트가 필요합니다.

 

우선 nuget패키지에서 tensorflow.net을 설치합니다.

.

그 다음 라이브러리를 사용하기 위해 using을 사용해서 텐서플로우 닷넷 라이브러리들을 로딩합니다.

 

.

그 다음에 opencvsharp도 포함해서 그림에 사각형을 그리고 글씨를 넣기로 합니다.

using OpenCvSharp;
 

 

opencv sharp에 관한 내용은 앞장을 참고하시면 됩니다.

https://easytocoding.tistory.com/7

 

opencvsharp 영상처리 프로그래밍(1) c# opencv

이번장에서 알아볼것은 opencv를 통해 c#에서 영상을 어떻게 처리하는지 알아볼것이다. opencv(Open Source Computer Vision Library)가 먼지 간략하게 설명하자면, ​ 크로스플랫폼(Windows, Linux, OS X(Mac),iOS,Andro

easytocoding.tistory.com

그 다음에 기존 텐서플로우 objectdetection에 학습된 모델로 검증하는 것만 할 것이기 때문에 기존에 학습된 데이터를 가져옵니다. 학습은 차후 장에 설명할것입니다.

string modelDir = "exported_model";
string pbFile = "frozen_inference_graph.pb";
string labelFile = "classes.pbtxt";
 

위의 학습은 tensorflow objectdetection으로 학습된것이다. 

검증에 쓰이는 이미지

그 다음에 form에 picturebox와 버튼하나 배치하고 버튼 눌르면 검증하도록 한다.

 

그 다음 버튼 이벤트를 추가해서

텐서를 로딩한다음 그래프를 그리고 그래프에서 이제 검증을 하고 검증된 데이터를 그림에 쓰는것까지 진행한다.

 

private Bitmap buildOutputImage(NDArray[] resultArr, Mat pic, float MIN_SCORE)
{
    PbtxtItems pbTxtItems = PbtxtParser.ParsePbtxtFile(labelFile);
    var scores = resultArr[2].AsIterator<float>();
    var boxes = resultArr[1].GetData<float>();
    var id = np.squeeze(resultArr[3]).GetData<float>();

    for (int i = 0; i < scores.size; i++)
    {
        float score = scores.MoveNext();
        if (score > MIN_SCORE)
        {
            float top = boxes[i * 4] * pic.Height;
            float left = boxes[i * 4 + 1] * pic.Width;
            float bottom = boxes[i * 4 + 2] * pic.Height;
            float right = boxes[i * 4 + 3] * pic.Width;
            if (id[i] == 21 || id[i] == 22 || id[i] == 11 || id[i] == 12)
            {
            }
            else
            {
                string name = pbTxtItems.items.Where(w => w.id == (int)id[i]).Select(s => s.name).FirstOrDefault();
                Cv2.Rectangle(pic, new Rect((int)left, (int)top, (int)(right - left), 
                    (int)(bottom - top)), new Scalar(0, 0, 255), 1);
                Cv2.PutText(pic, Convert.ToString((int)id[i]) + "_" + name + "_" + 
                    Convert.ToString((int)(score * 100)) + "%", new OpenCvSharp.Point((double)right, (double)bottom), 
                    HersheyFonts.HersheyComplex, 0.3, new Scalar(0, 0, 255), 1);
            }
        }
    }
    return BitmapConverter.ToBitmap(pic);
}
 

코드를 보면 알겠지만,

 

이미지 로딩하고 텐서를 읽어드린다음.

그래프에 인포팅하고 텐서를 찾아서 검증하는 식으로 이루어진다.

 

buildOutputImage()함수에서 MIN_SCORE점수를 정해서 현재 0.5로 해놓긴했는데 그점수 이상 되는 객체를 찾을 경우 표시할수 있게 코딩을 해논것이다 이건 커스텀마이징 해야된다.그래야 자신이 검증할거 검증안할거 정할수 있기 때문이다.

찾으면 이제 그 위치를 opencv의 사각형 그리는 함수로 표시하고 어떤걸 찾았는지 라벨을 put text()함수로 그린다. pbtext파일로 되어있어서 이걸 읽어드리는데 이거는 utilty함수에서 json으로 읽어드린다.

 

id넘버는 pbtext파일에 써있는 id넘버이다 이걸로 구분되므로 번호가 절대 중복안되도록 주의해야된다.물론 학습할때 이미 다 해놨을 테지만,

 

 

ReadTensorFromMat()함수는 mat파일에서 ndarray로 변환해줘서 텐서를 찾을 수 있도록 해줘야 된다.

 

 

 

참고: 반드시 주의 할 것은 64비트로 실행해야 된다 tensorflow.dll이 64비트로 검파일 되어있어서 32비트로 실행하면 badformatexception발생한다.

 

dll다운받는곳은 밑에 사진 참고.

 

 

반응형