Skip to content

**** ****

for my bad memories..

GNU utilities for Win32

2021-01-21


http://unxutils.sourceforge.net/

GNU 유틸리티중 유용한게 상당히 많은데..
이를 윈도우즈에서 사용할수 Win32로 포팅한 프로젝트가 GNU utilities for Win32 임.
물론 오래된 버전을 기준으로 하지만 dll 의존성 없이 딱딱 exe 하나만 있으면 사용가능하기에 아주 유용함.

먼저 아래의 파일을 받고.. usr/local/wbin 폴더내의 파일들 적당한곳에풀고
https://sourceforge.net/projects/unxutils/files/unxutils/current/UnxUtils.zip/download

다음 아래의 파일을 다운받아.. 기능개선 패치를 한다.
http://unxutils.sourceforge.net/UnxUpdates.zip

이제 사용하면된다.


Python 무설치 버전

2021-01-21


파이썬 공식 홈페이지에 무설치 버전을 제공하고 있음.
(https://www.python.org/downloads/release/python-391/)

아래로 쭉 내리다면 Windows embeddable package (64-bit) 이걸 받는다.

무설치 버전의 최고의 장점은 폴더채로 들고 다니면 어디서든 사용가능한 장점이 있음.
또 다른 응용 프로그램에 포함시켜서 파이썬의 기능을 이용할수도 있고..

어쨌든.. zip 파일을 다운받아 압축을 풀면 바로 사용가능함.
근데 문제는 pip 가 없다? pip가 없으면 외부 모듈 설치가 난감함.

pip 설치는 다음과 같이..
get-pip.py 를 아래에서 다운받아 적절한 폴더에 넣어둔다.
https://bootstrap.pypa.io/get-pip.py

다음 아래와 같이 설치한다.

C:\python-3.9.0-embed-amd64>python get-pip.py
Collecting pip
  Using cached pip-20.3.3-py2.py3-none-any.whl (1.5 MB)
Collecting setuptools
  Downloading setuptools-51.3.3-py3-none-any.whl (786 kB)
     |████████████████████████████████| 786 kB 1.6 MB/s
Collecting wheel
  Downloading wheel-0.36.2-py2.py3-none-any.whl (35 kB)
Installing collected packages: pip, setuptools, wheel
  WARNING: The scripts pip.exe, pip3.9.exe and pip3.exe are installed in 'C:\python-3.9.0-embed-amd64\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The scripts easy_install-3.9.exe and easy_install.exe are installed in 'C:\python-3.9.0-embed-amd64\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script wheel.exe is installed in 'C:\python-3.9.0-embed-amd64\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-20.3.3 setuptools-51.3.3 wheel-0.36.2

C:\python-3.9.0-embed-amd64>

이제 모듈을 설치할려고하니.. 이런 에러가..

C:\python-3.9.0-embed-amd64>Scripts\pip.exe install python-pptx
Traceback (most recent call last):
  File "runpy.py", line 197, in _run_module_as_main
  File "runpy.py", line 87, in _run_code
  File "C:\python-3.9.0-embed-amd64\Scripts\pip.exe\__main__.py", line 4, in <module>
ModuleNotFoundError: No module named 'pip'

파이썬 폴더에 보면 python39._pth 파일이 있는데 이 파일 마지막에 아래를 추가.

lib\site-packages

다시 설치하면

C:\python-3.9.0-embed-amd64>scripts\pip install python-pptx
Collecting python-pptx
  Downloading python-pptx-0.6.18.tar.gz (8.9 MB)
     |████████████████████████████████| 8.9 MB 6.4 MB/s
Collecting lxml>=3.1.0
  Downloading lxml-4.6.2-cp39-cp39-win_amd64.whl (3.5 MB)
     |████████████████████████████████| 3.5 MB ...
Collecting Pillow>=3.3.2
  Downloading Pillow-8.1.0-cp39-cp39-win_amd64.whl (2.2 MB)
     |████████████████████████████████| 2.2 MB ...
Collecting XlsxWriter>=0.5.7
  Downloading XlsxWriter-1.3.7-py2.py3-none-any.whl (144 kB)
     |████████████████████████████████| 144 kB ...
Building wheels for collected packages: python-pptx
  Building wheel for python-pptx (setup.py) ... done
  Created wheel for python-pptx: filename=python_pptx-0.6.18-py3-none-any.whl size=275704 sha256=968c6fae2111efebcae960370fb4ed5ceb311d0fa762f19fc82a9994aba754b6
  Stored in directory: c:\users\ihmin\appdata\local\pip\cache\wheels\94\b7\70\0c19e32b072e500447ae9a17df9389fc046973ef1df8b0c239
Successfully built python-pptx
Installing collected packages: XlsxWriter, Pillow, lxml, python-pptx
Successfully installed Pillow-8.1.0 XlsxWriter-1.3.7 lxml-4.6.2 python-pptx-0.6.18

정상 설치됨.


ffmpeg 프레임 추출 예제

2021-01-18


ffmpeg 을 이용한 비디오 파일에서 첫 다섯개의 프레임 이미지 추출 예제..

makefile

all:
	gcc ./test.c -I/c/Temp/ffmpeg_win65/include -L/c/Temp/ffmpeg_win64/lib -lavformat -lavcodec -lswscale -lavutil -lswresample -lz -lbcrypt -lole32 -lMfplat -ltiff -liconv -llzma -lws2_32 -lSecur32 -lbz2 -lstrmiids

test.c

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <stdio.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
  FILE *pFile;
  char szFilename[32];
  int  y;
  
  // Open file
  sprintf(szFilename, "frame%d.ppm", iFrame);
  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
    return;
  
  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
  
  // Write pixel data
  for(y=0; y<height; y++)
    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
  
  // Close file
  fclose(pFile);
}

int main(int argc, char *argv[]) {
  // Initalizing these to NULL prevents segfaults!
  AVFormatContext   *pFormatCtx = NULL;
  int               i, videoStream;
  AVCodecContext    *pCodecCtxOrig = NULL;
  AVCodecContext    *pCodecCtx = NULL;
  AVCodec           *pCodec = NULL;
  AVFrame           *pFrame = NULL;
  AVFrame           *pFrameRGB = NULL;
  AVPacket          packet;
  int               frameFinished;
  int               numBytes;
  uint8_t           *buffer = NULL;
  struct SwsContext *sws_ctx = NULL;

  if(argc < 2) {
    printf("Please provide a movie file\n");
    return -1;
  }
  // Register all formats and codecs
  av_register_all();
  
  // Open video file
  if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
    return -1; // Couldn't open file
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, argv[1], 0);
  
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return -1; // Didn't find a video stream
  
  // Get a pointer to the codec context for the video stream
  pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
  }
  // Copy context
  pCodecCtx = avcodec_alloc_context3(pCodec);
  if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }

  // Open codec
  if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
    return -1; // Could not open codec
  
  // Allocate video frame
  pFrame=av_frame_alloc();
  
  // Allocate an AVFrame structure
  pFrameRGB=av_frame_alloc();
  if(pFrameRGB==NULL)
    return -1;

  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
            pCodecCtx->height);
  buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

  // Assign appropriate parts of buffer to image planes in pFrameRGB
  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  // of AVPicture
  avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
     pCodecCtx->width, pCodecCtx->height);
  
  // initialize SWS context for software scaling
  sws_ctx = sws_getContext(pCodecCtx->width,
         pCodecCtx->height,
         pCodecCtx->pix_fmt,
         pCodecCtx->width,
         pCodecCtx->height,
         AV_PIX_FMT_RGB24,
         SWS_BILINEAR,
         NULL,
         NULL,
         NULL
         );

  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0) {
	  // Is this a packet from the video stream?
	  if(packet.stream_index==videoStream) {
		  // Decode video frame
		  avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
		  // Did we get a video frame?
		  if(frameFinished) {
			  //avcodec_align_dimensions2 (pCodecCtx, &pCodecCtx->width, &pCodecCtx->height, pFrameRGB->linesize);

			  // Convert the image from its native format to RGB
			  sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
					  pFrame->linesize, 0, pCodecCtx->height,
					  pFrameRGB->data, pFrameRGB->linesize);

			  // Save the frame to disk
			  if(++i<=5)
				  SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
		  }
	  }

	  // Free the packet that was allocated by av_read_frame
	  av_free_packet(&packet);
  }
  
  // Free the RGB image
  av_free(buffer);
  av_frame_free(&pFrameRGB);
  
  // Free the YUV frame
  av_frame_free(&pFrame);
  
  // Close the codecs
  avcodec_close(pCodecCtx);
  avcodec_close(pCodecCtxOrig);

  // Close the video file
  avformat_close_input(&pFormatCtx);
  
  return 0;
}

FBVector

2021-01-05


페이스북에서 공개한 FBVector..
(https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md)
FBVector는 folly의 일부분으로 std::vector 를 대체하기위한 용도.
(folly는 C++의 std나 boost 라이브러리의 일부분을 개선하거나 대체 용도로 개발된 클래스 모음.)

일단 테스트해보니.. 속도면에서 상당한 개선이..

{
	std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

	folly::fbvector<unsigned int> vec;
	for(int i=0; i<1000000000; i++) {
		vec.push_back(i);
	}

	std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
	std::cout << "FBVector: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

	std::cout << "Press any key to next test." << std::endl;
	getchar();
	
	vec.clear();
	vec.shrink_to_fit();
}

{
	std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

	std::vector<unsigned int> vec;
	for(int i=0; i<1000000000; i++) {
		vec.push_back(i);
	}

	std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
	std::cout << "Vector: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

	std::cout << "Press any key to exit." << std::endl;
	getchar();

	vec.clear();
	vec.shrink_to_fit();
}

실행..

FBVector: Time passed (sec) : 9.05379 seconds
Press any key to next test.

Vector: Time passed (sec) : 16.3373 seconds
Press any key to exit.

ccache

2021-01-05


컴파일 속도 올리는 프로그램중 ccache 를 테스트해봄.

우선 ccache 설치

pacman --needed -S mingw-w64-x86_64-ccache

다음 .bashrc 에 추가

export USE_CCACHE=1
export CCACHE_DIR=/var/ccache-cache
export CCACHE_LOGFILE=/var/log/ccache.log

qmake의 pro 파일의 경우.. 아래를 추가

QMAKE_CXX=ccache g++

이제 컴파일을 하면..
첫번째 컴파일에는 캐시를 만드느라 시간이 들지만..
두번째부터는.. 엄청 빠른 시간에 컴파일을 수행함.


Single-pass Wireframe Rendering

2020-12-23


OpenGL 에서 정말 난이도가 높은것 중 하나가 와이어프레임을 그리는것이라 생각함..
이유는 면위에 선을 그리는거 자체가 간섭이 일어나기에 선이 제대로 보이지 않고..
면을 Offset 하지 않으면 도통 깨끗한 라인을 볼수 없다는것.. (OpenGL에서 선을 offset 하는 기능은 없음)
이것도 문제가 면을 Offset 하기 때문에 간혹 면과 다른 면의 선이 간섭이 발생하는것처럼 보이기도함..
그래서 선을 geometry 스테이징에서 아주 앏은 quad로 변환하여 Offset 해도 마찬기로 간섭이 발생하는것처럼 보이기도함..
어쨌던 이래나 저래나 Wireframe을 그리는 단계가 추가되기 때문에 속도 저하가 아주 약간이라도 있기마련..

면을 그릴때 선을 같이 쉐이더에서 그릴수는 없을까 생각하다 구글링을 해보니.. 아래의 논문이 보임..

imm4884.pdf

확인해보니.. fragment 스테이징에서 primitive의 최외각을 추출해서 선을 그려주는 아주 간단하면서
속도 저하가 없는 아주 깨끗한 라인을 그릴수 있는 기법이란걸 알앗음.

해당 논문을 구현한 싸이트가 보이는데..
http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.html
http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_11.html

혹시 싸이트가 언제 짤릴지 모르니 아래는 백업 pdf…
Clipping Space_ Single-Pass Wireframe Rendering.pdf
Clipping Space_ Single-Pass Wireframe Rendering Explained and Extended.pdf

최종 구현 결과는…


OpenCascade 란?

2020-11-28


요즘 Mesh 데이타를 다루고 있는데 OpenCascade 라는 오픈소스가 유독 눈에 띈다.
일단 지금까지 파악한 바로는 캐드 데이타를 뷰잉/편집 하는 용도의 API가 오픈되어 있는 오픈소스 툴킷이다. OpenCascade는 오픈소스 진영에서 유일한 BRep 커널이다. BRep 개념은 https://m.blog.naver.com/fslin_/220942411389 여기서 보자.

Mesh 데이타를 다룰려면 OpenCascade를 사용할일은 없다. (캐드 데이타는 Mesh 개념이 아니라 BRep 라는 개념을 사용한다.)
OpenCascade 는 본래 80년대에 유클리드라는 CAD 제품을 개발/판매 사업을 하다 도저히 메이저 회사에 비빌 재간이 안되서 직접 개발했던 CAD 커널을 OpenCascade로 공개한다.
코드를 공개하는대신 OpenCascade를 사용하려는 유저로부터의 교육이나 기술지원으로 먹고살고 있으며 상당히 성공적으로 지금까지 유지되고 있다.
(국내 Midas는 초기 OpenCascade를 사용하다 규모가 커지면서 유료인 Parasolid 커널로 대체하였다.)
암튼 소규모 캐드 프로그램을 만들기엔 OpenCascade 만한게 없는거 같다.

참고로 OpenCascade는 캐드 데이타를 삼각 메시로 변환해주는 API를 제공한다.
Mesh 데이타를 취급하는 프로그램에서 IGES나 STEP 같은 캐드 파일을 볼러올수 있단 얘기다.
물론 Mesh 프로그램에서 중요한 요소 퀄리티는 찾아볼수 없지만…
이렇게 불러들인 Mesh 데이타는 반드시 리메싱 과정이 필요할것이다.

아래는 OpenCascade의 API를 사용해서 IGES 파일을 메시 데이타로 변환하여 불러와봤다.


pacman 업데이트 에러

2020-07-27


오늘 msys2의 pacman 으로 시스템 업그레이드를 하려 하는데..
아래와 같이 에러가 나옴.

:: Synchronizing package databases...
downloading mingw32.db...
downloading mingw32.db.sig...
error: mingw32: key "4A6129F4E4B84AE46ED7F635628F528CF3053E04" is unknown
...

검색해보니 아래와 같이 처리 하라함. (참고: https://www.msys2.org/news/#2020-06-29-new-packagers)

# curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz
# curl -O http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig
# pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz{.sig,}
# pacman -U --config <(echo) msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz
# rm -r /etc/pacman.d/gnupg/
# pacman-key --init
# pacman-key --populate msys2

다음 msys2 를 재시작.