네트워크 드라이브 상에 파일 저장시 속도 저하 문제
글쓴이: shin2012 / 작성시간: 월, 2014/12/29 - 11:01오전
일단 첫인사 먼저 드립니다!
눈팅은 항상 많이 했는데 가입은 오늘에서야 했네요 잘 부탁드립니다!
앞으로 열심히 활동하겠습니다 ;)
==============
다름이 아니라 여쭤보고 싶은게 있는데, 제가 지금 회사에서 라인스캔 카메라의 이미지를 취득해서 이미지 프로세싱을 하는 프로그램을 개발중입니다.
이제 시작단계예요.
라인스캔 카메라에서 이미지를 받아 파일로 저장하는데 이 파일의 용량은 각각 32MB 이고 1초에 5장정도 들어옵니다.
이 이미지들을 먼저 버퍼에 저장해 두고 별도의 스레드가 계속 버퍼를 감시하면서 버퍼에 내용이 있을 경우 openCV의 cvSaveImage 함수를 이용해서 저장합니다.
이 방법으로 로컬에 저장할 때는 하나도 놓치는 것 없이 정상적으로 저장이 됩니다.
그런데 이 이미지를 같은 프로그램으로 경로만 네트워크에 있는 드라이브로 지정을 했을 뿐인데 도저히 따라가지를 못합니다.
저장속도에는 전혀 문제가 없는 상태인데도요.
(10Gbps 랜으로 2개의 컴퓨터가 연결되어 있고, 양쪽 컴퓨터 모두 SSD4개를 RAID0로 묶어둔 상태입니다. 20기가짜리 파일을 그냥 복사해보면 초당 900MB/s 정도로 전송이 가능합니다.)
혹시 짐작가는 원인이 있으신지 조언을 구합니다!
일단 필요없는 부분 빼면 그다지 길지 않은 코드라서 전체 코드를 첨부해 봅니다.
// ===================================================================================== // == Silicon Software사의 VD4CL FG board와 DALSA 카메라를 이용한 이미지 취득 프로그램 // ===================================================================================== #include <iostream> #include <stdio.h> #include <time.h> // 수행시간 측정 위해 사용 #include "board_and_dll_chooser.h" #include "fgrab_struct.h" #include "fgrab_prototyp.h" #include "fgrab_define.h" #include "SisoDisplay.h" #include "SisoIO.h" #include "highgui.h" // OpenCV Library #include <windows.h> #define nOfBuffer 100 // 이미지 버퍼 개수 정의 //=== 이미지 버퍼 구조체 typedef struct _buffer{ int head; int tail; int idx[nOfBuffer]; IplImage* image[nOfBuffer]; }Buffer; Buffer ImageBuffer; //=== 기타 이미지 변수 세팅 IplImage* OutImg; // 저장 전 이미지 임시보관변수 void* ImagePtr; // 프레임그래버에서 넘어온 이미지 포인터 int nOfDropped = 0; // Drop된 총 프레임 수 char fname[100]; // 결과값 출력을 위한 파일명 //=== 카메라 기본 변수값 Fg_Struct *fg = NULL; int boardNr = 0; //selectBoardDialog(); int camPort = PORT_A; frameindex_t nrOfPicturesToGrab = 1000; frameindex_t nbBuffers = 4; unsigned int width = 4096; unsigned int height = 16*1024; int samplePerPixel = 1; size_t bytePerSample = 1; using namespace std; DWORD WINAPI BufferToFile(void *arg); // 버퍼의 내용을 파일로 출력 int ImageToBuffer(void* ImgPointer, frameindex_t cur_pic_nr); // 프레임그래버에서 넘어온 이미지를 버퍼에 저장 int main(int argc, char* argv[], char* envp[]) { //=== [프로그램명] help 명령시 사용법 출력 if (argc == 2){ if (strcmp(argv[1], "help") == 0) { cout << "Usage: " << argv[0] << " [보드번호]" << endl; cout << "Usage: " << argv[0] << " [보드번호] [Width] [Height] [Grab할 이미지 수]" << endl; return 0; }else{ boardNr = atoi(argv[1]); } } //=== 적절한 Argument들이 입력되었을 때 변수 세팅 if (argc == 5) { cout << "== 카메라 설정==" << endl; cout << "Frame Grabber 보드 번호 : " << argv[1] << endl; cout << "이미지 크기 : " << argv[2] << "x" << argv[3] << endl; cout << "취득할 이미지 수 : " << argv[4] << endl; boardNr = atoi(argv[1]); width = atoi(argv[2]); height = atoi(argv[3]); nrOfPicturesToGrab = atoi(argv[4]); }else{ cout << "* 실행파라미터가 입력되지 않았으므로 기본값으로 실행합니다." << endl; cout << "== 카메라 설정==" << endl; cout << "Frame Grabber 보드 번호 : " << boardNr << endl; cout << "이미지 크기 : " << width << "x" << height << endl; cout << "취득할 이미지 수 : " << nrOfPicturesToGrab << endl; } //=== 버퍼 메모리 할당 int i; for (i=0 ; i<nOfBuffer ; i++){ ImageBuffer.image[i] = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1); } // 프레임그래버 인식부 const char *applet; switch (Fg_getBoardType(boardNr)) { case PN_MICROENABLE4AS1CL: applet = "SingleAreaGray16"; break; case PN_MICROENABLE4AD1CL: case PN_MICROENABLE4AD4CL: case PN_MICROENABLE4VD1CL: case PN_MICROENABLE4VD4CL: applet = "FullLineGray8"; break; case PN_MICROENABLE4AQ4GE: case PN_MICROENABLE4VQ4GE: applet = "QuadAreaGray16"; break; case PN_MICROENABLE3I: applet = "DualAreaGray"; break; case PN_MICROENABLE3IXXL: applet = "DualAreaGray12XXL"; break; default: applet = "DualAreaGray16"; break; } if ((fg = Fg_Init(applet, boardNr)) == NULL) { fprintf(stderr, "error in Fg_Init: %s\n", Fg_getLastErrorDescription(NULL)); return FG_ERROR; } size_t totalBufferSize = width * height * samplePerPixel * bytePerSample * nbBuffers; dma_mem *memHandle = Fg_AllocMemEx(fg, totalBufferSize, nbBuffers); if (memHandle == NULL) { fprintf(stderr, "error in Fg_AllocMemEx: %s\n", Fg_getLastErrorDescription(fg)); Fg_FreeGrabber(fg); return FG_ERROR; } /*Image width of the acquisition window.*/ if (Fg_setParameter(fg,FG_WIDTH,&width,camPort) < 0 ) { fprintf(stderr, "Fg_setParameter(FG_WIDTH) failed: %s\n", Fg_getLastErrorDescription(fg)); Fg_FreeMemEx(fg, memHandle); Fg_FreeGrabber(fg); return FG_ERROR; } /*Image height of the acquisition window.*/ if (Fg_setParameter(fg,FG_HEIGHT,&height,camPort) < 0 ) { fprintf(stderr, "Fg_setParameter(FG_HEIGHT) failed: %s\n", Fg_getLastErrorDescription(fg)); Fg_FreeMemEx(fg, memHandle); Fg_FreeGrabber(fg); return FG_ERROR; } int bitAlignment = FG_LEFT_ALIGNED; if (Fg_setParameter(fg,FG_BITALIGNMENT,&bitAlignment,camPort) < 0) { fprintf(stderr, "Fg_setParameter(FG_FG_BITALIGNMENTHEIGHT) failed: %s\n", Fg_getLastErrorDescription(fg)); Fg_FreeMemEx(fg, memHandle); Fg_FreeGrabber(fg); return FG_ERROR; } if ((Fg_AcquireEx(fg, camPort, nrOfPicturesToGrab+1, ACQ_STANDARD, memHandle)) < 0) { fprintf(stderr, "Fg_AcquireEx() failed: %s\n", Fg_getLastErrorDescription(fg)); Fg_FreeMemEx(fg, memHandle); Fg_FreeGrabber(fg); return FG_ERROR; } //=== 버퍼->파일저장 스레드 실행 HANDLE hThread; DWORD dwThreadID; hThread = CreateThread(NULL, 0, BufferToFile, NULL, 0, &dwThreadID); //=== 루프 수행시간 계산 시작 clock_t startTime, endTime; double nProcessExecuteTime; startTime = clock(); //=== 버퍼 사용량 출력 위한 파일 핸들 오픈 char BufferResult[50]; sprintf_s(BufferResult,"BufferLoad_FG%d.csv",boardNr); FILE* BufferLoad = fopen(BufferResult, "w"); frameindex_t last_pic_nr = 0; frameindex_t cur_pic_nr; int timeout = 4; while ((cur_pic_nr = Fg_getLastPicNumberBlockingEx(fg, last_pic_nr + 1, camPort, timeout, memHandle)) < nrOfPicturesToGrab+1) { if (cur_pic_nr < 0) { fprintf(stderr, "Fg_getLastPicNumberBlockingEx(%li) failed: %s\n", last_pic_nr + 1, Fg_getLastErrorDescription(fg)); Fg_stopAcquire(fg,camPort); Fg_FreeMemEx(fg, memHandle); Fg_FreeGrabber(fg); return FG_ERROR; } if(cur_pic_nr != last_pic_nr + 1){ printf("***** %d frame dropped !!!\n",cur_pic_nr-last_pic_nr-1); nOfDropped += cur_pic_nr-last_pic_nr-1; }else{ ImagePtr = Fg_getImagePtrEx(fg, cur_pic_nr, camPort, memHandle); ImageToBuffer(ImagePtr, cur_pic_nr); // 이미지->버퍼 // 버퍼 사용량 계산 및 출력 if (ImageBuffer.head < ImageBuffer.tail){ fprintf(BufferLoad,"%d\n", ImageBuffer.tail-ImageBuffer.head); }else{ fprintf(BufferLoad,"%d\n", ImageBuffer.tail+nOfBuffer-ImageBuffer.head); } } last_pic_nr = cur_pic_nr; } fclose(BufferLoad); // 버퍼 사용량 출력 끝 //== 루프 종료 시간 계산 endTime = clock(); nProcessExecuteTime = ((double)(endTime - startTime)) / CLOCKS_PER_SEC; //== 버퍼->파일저장 스레드 종료 대기 printf("저장 스레드 수행을 위해 10초간 대기합니다....\n"); WaitForSingleObject(hThread, 10000); //== 결과 출력 (파일) char result_file[50]; sprintf_s(result_file,"result_FG%d.txt",boardNr); FILE* resulttext = fopen(result_file, "w"); fprintf(resulttext, "==FG Board %d==\n수행시간 : %f\n", boardNr,nProcessExecuteTime); fprintf(resulttext, "Dropped Images : %d\n", nOfDropped); fclose(resulttext); //== 결과 출력 (스크린) cout << "== FG Board " << boardNr << "==" << endl; cout << "수행시간 : " << nProcessExecuteTime << endl; cout << "# of Dropped Image : " << nOfDropped << endl; Fg_stopAcquire(fg,camPort); Fg_FreeMemEx(fg, memHandle); Fg_FreeGrabber(fg); return FG_OK; } DWORD WINAPI BufferToFile(void *arg) { OutImg = cvCreateImageHeader(cvSize(width,height),IPL_DEPTH_8U,1); while(1){ if (ImageBuffer.head == ImageBuffer.tail){ // 버퍼 비어있음! }else{ OutImg->imageData = ImageBuffer.image[ImageBuffer.head]->imageData; sprintf_s(fname,"D:\\FG%d\\%d.bmp", boardNr, ImageBuffer.idx[ImageBuffer.head]); cvSaveImage(fname, OutImg); printf("버퍼에서 추출 %d %s\n", ImageBuffer.head, fname); ImageBuffer.head = (ImageBuffer.head+1) % nOfBuffer; } } return 0; } int ImageToBuffer(void* ImgPointer, frameindex_t cur_pic_nr){ if (((ImageBuffer.tail+1)%nOfBuffer) == ImageBuffer.head){ cout << "Image Buffer Overflow!" << endl; }else{ cvSetData(ImageBuffer.image[ImageBuffer.tail],ImgPointer,ImageBuffer.image[ImageBuffer.tail]->width * ImageBuffer.image[ImageBuffer.tail]->nChannels); ImageBuffer.idx[ImageBuffer.tail] = cur_pic_nr; printf("버퍼에 저장 ENQUEUE %d\n",ImageBuffer.tail); ImageBuffer.tail = (ImageBuffer.tail+1)%nOfBuffer; } return 0; }
Forums:
댓글 달기