이미지 리사이즈에 대한 짧은(?) 고민

0. 이미지 리사이즈?

 디지털 형태로 저장되어 있는 비트맵 형태의 이미지의 크기를 줄이거나 늘리는 작업을 통털어 이미지 리사이즈라고 흔히 칭한다. 조금이라도 관심이 있는 사람들이라면 이미지 리사이즈도 프로그램, 옵션 등등에 따라 각기 특징이 있고, 퀄러티 차이도 존재하며, 2~3년 전 부터는 포토샵을 이용한 다단계 리사이즈에 대한 말들도 많이 나오고 있다.

 간단해만 보이는, 이미지의 크기 줄이기(혹은 늘이기)에도 복잡한 사정이 많이 있다. 줄이기와 늘이기도 또 판이하게 다르기도 하고 말이다. '까짓거 그냥 줄이며 되는거지'라고 생각할 수도 있겠다.

 흔히 말하는 '언샵 마스크(일종의 샤프닝-Sharpening)필터를 단계마다 삽입하는 다단계 리사이즈'는, '이렇게 해보니 좋더라' 라는 결과적인 측면이 강조된 방법이라하겠다. 샤프닝은 원본을 망가뜨릴 가능성도 크고, 특히나 픽셀단위의 노이즈에 취약할 수 있다는 문제도 있다. (하지만, 이 방법이 좋다는 사람들에게 틀렸다고 말할 수도 없는, 애매한 문제이다)



1. 1픽셀을, 1점의 샘플로 볼 것인가? 면적으로 볼 것인가?

 이미지 리사이즈를 픽셀단위의 처리까지 직접 프로그램 해본 사람이라면 한번쯤 고민하지 않을 수 없는 문제이다. 단순하지 않은 문제일 수도 있고, 어쩌면 당연히 두가지를 따로이 각기 고려해야 한다고 볼 수도 있다.

 1픽셀을 면적으로 본다는 것은, 흔히 생각할 수 있는, 확대된 비트맵 이미지의 네모 모양의 면적으로 본다는 말이다. 이미지를 축소할 경우를 생각해보면, 몇개의 픽셀이 1개의 픽셀로 줄어들게 된다. 이럴 경우 1개의 새로운 픽셀의 값은 그 픽셀에 해당되는 이전의 많은 픽셀들의 값이 적절히 섞여 나오게 된다. 정수개가 아닐 수도 있고, 이전 픽셀의 조각이 중간에 잘려서 새로운 픽셀에 나뉘어 들어갈 수도 있겠다.
 혹은 사각의 모양이 아닌, 바이리니어 필터로 확대한 모습이라던가 여타의 희미한 형태의 확대 이미지도 고려할 수 있겠다. 하지만 역시 기본적으로는 새로운 픽셀이 덮게 되는 이전 픽셀의 면적들의 컬러값들을 적분한 값을 새로운 픽셀의 값으로 산출해내는 방법 자체는 동일하다고 볼 수 있겠다.

 또 다른 경우는, 1픽셀을 1점의 샘플로 보는 경우이다. 이것은 사운드의 샘플링 이론과 비슷하게, 1개의 샘플은 그 좌표에서 따낸 면적 0인 한 점의 색을 나타낸다고 보는 것이다. 이러할 경우 샘플링 이론에서 배우는 나이키스트 이론이라던가, 여타의 주파수에 관련된 이론 따위가 모두 적용이 가능하며, 리샘플 필터 역시 모두 비슷한 형태로 적용이 가능하게 된다. sinc 리샘플이니 하는 것들이 바로 이러한 시각으로 구현된 것들이다.
 하지만 이미지에는 실제로 샘플링이나 사운드에서 사용되는 'sinc(x) = sin(x)/x ' 함수, 혹은 brickwall filter를 사용하지는 못한다. 이럴 경우 경계면에서 흔히 발생하는 ringing이 (사운드일 경우에는 귀로 느낄 수 없지만) 눈에 너무 거슬리는 물결무늬로 나타나게 된다. 따라서 해당 필터들보다는, 인터폴레이션용의 필터들, 예를 들어 Lanczos 따위가 주로 사용되게 된다.



2. 이미지 축소

 축소는, 이미지의 크기를 줄이면서도 최대한 많은 정보를 손실 없이 담으면서, 표현할 수 없는 부분을 cut하여 노이즈를 효과적으로 줄일 수 있어야 한다.

 사실 이러한 설명은, 위에서 말한, 1픽셀을 1샘플로 인식하는 경우에 더 가깝다고 볼 수 있다. 이럴 경우 나이키스트 이론에 충실하게, 해당 해상도가 담아낼 수 있는 이상의 정보(1픽셀 이하)를 전부 급격한 LPF(Low Pass Filter)로 처리하고, 해당 결과 중, 다시 새로운 해상도의 픽셀에 해당되는 위치의 샘플을 다시 값을 따오는 작업을 하는 것이다. 이것을 resample이라 하여, lanczos 따위의 필터들을 사용한다는 프로그램들이 사용하는 방법이 된다.

 bilinear도 따지고 보면 1픽셀을 1점으로 보아서, 해당 점으로부터의 거리를 계산하여 linear하게 평균을 내는 방법을 사용하게 된다. 이러한 형태의 fir 필터를 만들고자 하면 만들 수 있겠지만, 그다지 좋은 방법은 아닐 것 같다. (...) bicubic 역시 비슷한 접근이 될 것 같고 말이다.

 1픽셀을 면적으로 보고 처리하는 방법은.. 이 블로그에서 다운받을 수 있는 자작 프로그램의 Subsample Average 옵션으로 테스트가 가능하다. 일단 이론상으로는 1개의 픽셀을 1개의 미세한 사각형으로 보고, 새로 만들어질 해상도 이미지의 1픽셀도 1개의 미세한 사각형으로 보아 해당 방법으로 색을 정확히 섞어내는 방법으로 리사이즈를 한다. 사각형이 아니라 다른 형태라면 또 다른 결과가 나오겠지만.. 큰 차이는 없지 않을까? 암튼 시간 나면 그런 방법도 시도해볼 예정.

 아무튼, 앞에서 설명한 프로그램을 한번 테스트 해보기 바란다. Lagrange 인터폴레이션 필터를 사용한 리샘플은, (FIR 필터의 길이가 제법 긴 만큼..) 노이즈 제거나 선예도에서도 상당한 효과를 볼 수 있을 것이다.

 그리고 개인적으로는 언샤픈마스크(샤프닝)을 사용한 다단계 리사이즈를 추천하지는 않는다. 역시 원본을 심히 왜곡시킬 수 있다는 점에서 말이다.


2.1.1. 축소 테스트(패턴)

 다음과 같은 이미지를 사용하기로 하였다. 흰색과 검은색 픽셀이 교차로 배치되어 빡빡히 들어찬 이미지가 되겠다.

     


 이 이미지를 4배 확대하면.. 다음과 같다.

   


 위의 작은 원본(확대한 것 말고..) 이미지를 2/3, 즉 1/1.5로 축소하기로 하였다. 새로운 하나의 픽셀이 기존의 1.5x1.5개의 픽셀을 덮게 되는 것이다. 각 축소 리사이즈 방법은 각기 명확히 다른 결과들을 보여주고 있다.
 결과 이미지는 다시 4배로 확대하여 보기 좋도록 한 것이니 오해 없으시길.



 첫번째로, Bilinear Resize
 
    

 고르지 못한 무늬를 보여주고 있다. 주위 4개의 픽셀로부터 거리에 따라 계산되는 점의 색은 한 픽셀을 건너뛸 때 마다 조금씩 달라지게 되므로 이러한 결과를 보여준다.




 두번째로, Subsample Average

   

 Bilinear Resize보다는 낫지만, 역시 규칙적인 무늬가 나타나고 있다. 픽셀을 면적으로 보는 방식에서 오는 어쩔 수 없는 결과이다.



 세번쨰로, Lanczos Resample

   

 앞의 두 방식에 비해 훨씬 균일한 이미지를 보여준다. 1/1.5배의 해상도에서 나타날 수 없는 체스판무늬를 필터링하여 제거한 결과가 이렇게 되는 것이다. 여전히 나타나고 있는 희미한 격자무늬는 필터 특성이라 해야겠다.



 마지막으로, Lagrange Resample

   

 거의 균일한 이미지를 보여주고 있다. lanczos보다 좀 더 ideal한 brickwall filter에 가깝다고 보아야 할까. 문제는, 글씨 등의 짙은 경계면에서 약간의 ringing이 나타난다는 것인데, 사진에서는 거의 알아보기 힘들 정도일 것이다. 어차피 최종 판단은 유저들의 몫.




2.1.2. 축소 테스트(이미지)

자. 원본이다. 클릭하면 큰 이미지 볼 수도 있고 저장도 가능하니 받아서 각자 직접 테스트도 가능하겠다.

   

 나뭇잎, 바위, 꽃잎, 잎사귀, 풀 등을 보면 되겠다. 안타깝게도 노이즈는 안나왔다. (테스트 따로 해야되나?)
 각각 510, 242로 리사이즈 하여 결과물을 뽑아보았다.



 첫번째, bilinear resize

    
   

 바위의 표면이 거칠게 질감이 살아나 보이지만, 샘플을 제대로 평균내지 못하여 거칠게 나타나는 것 뿐이다. 바이리니어 리사이즈는 많은 샘플을 따내지 못하니까 정밀한 리사이즈는 아니다.


 두번째, subsample average

   
   

 그림이 작아진만큼.. 질감이 많이 죽고 있는건 사실이지만, 나름 모든 샘플들이 다 사용되어서 비교적 정밀한 편이라고 할 수 있다.




 세번째 lanczos resample

   
   

 인기 있는 리사이즈 방법인 만큼 좋은 성능을 보여주고 있다.




 네번째 lagrange resample

   
   

 lanczos보다 약간이지만, 좀 더 또렷한 질감을 보여준다. 저장해서 확대해서 확인해보아도 좋을 듯.




3. 이미지 확대

 어떠한 리사이즈도 원본보다 많은 데이터를 담아낼 수 없다. 아무리 확대하고 싶어도, 1장의 그림에서 뽑아낼 수 있는 데이터의 량은 정해져 있으므로, 확대는 그냥 확대일 뿐 더 또렷해지거나 보이지 않던 것이 보이는 일은 없다.
 가끔 요새 보이는 S-Spline 리샘플이라 불리는 방법은, 윤곽선을 찾아내어 해당 부분을 별도로 처리하는 방법이 아닌가 싶다. 하지만 이러한 방식에도 문제는 항상 존재하겠지. (Threshold 값이 존재한다는 것 자체가 문제를 일으킬 수 있다는 증거 쯤 되지 않나 싶다.)
 하지만 역시 위에서 설명했듯이, 확대한다고 해서 또렷해지지 않는 문제 때문에 잘 사용되는 일은 없겠다. 대부분의 사람들이 디카로 촬영한 거대한 이미지를 웹용으로 축소하는데 이미지 리사이즈 프로그램들을 많이 사용하고 있으니 말이다.


3.1.1. 확대 테스트(패턴)

 축소테스트에서 사용했던 1x1 체스판 이미지를 다시 사용하였다. 다만 확대 후 옆의 불필요한 부분을 잘라내고 표시.

   


첫번째, Bilinear Resize의 결과

   



두번째, Lanczos Resample

   



마지막으로, Langrange Resample

   


 확대 이미지는 따로 가타부타를 따질만한 상황은 아니겠다. 어차피 잃어버린 정보는 없을 것이라 판단되니까.



 또하나의 테스트. 원본은 다음과 같다. (잘 안보이더라도 이해를....)

   


 첫번째, Bilinear Resize

   



 두번째, Lanczos Resample

   



세번째, Lagrange Resample

   

 필터 특성에 따른 링잉이 확대시 이렇게 나타나고 있다. 흑-백이 갈리는 명확한 경계면에서의 링잉이 나타나게 되므로, 이러한 부분이 나타나는 이미지에서는 최선의 선택은 아니겠다.




3.1.2. 확대 테스트(이미지)


 일단 원본.

   

 축소 테스트에서 사용한 이미지의 일부를 1/2로 줄여서 좀 더 쨍~하게 만든 샘플. 각 10배 확대.


 첫번째. bilinear resize






두번째. lanczos resample







 세번째. lagrange resample.






4. 마치며..

 글쎄. 짧게 쓴다고 시작했는데.. 짧지 않게 되어버렸구만. -_-;

 http://openwrld.egloos.com/862897

 암튼 한번 써보삼~!

by openwrld | 2008/06/18 17:41 | 트랙백 | 덧글(2)

HDTV 인코딩 영상 전처리

 HDTV를 녹화해야 할 일이 가끔 있다. 다큐멘터리 녹화할 일도 있겠고, 시사 프로그램, 드라마 등등.

 어쨌든 녹화했으니 이걸 적당한 크기와 포맷으로 인코딩을 해야 하는데, 인코딩 전의 전처리가 그 인코딩 된 후의 결과를 좌우하겠지. 아무리 성능 좋은 코덱이라도 그 인코딩 전의 상태가 인코딩 효율을 결정하게 된달까.

 여기에서 소개하는 방법은 용량을 포기한 최상의 화질을 위한 방법은 아니다. 용량대 화질 비율을 최대한 높이는 것은 맞지만, 사람들끼리 돌려보기 위한, 적당한 크기와 용량의 동영상을 만들기 위한 것이니 그리 아시고 보시면 되겠다. 뭐, 활용은 하기 나름이겠고.


 주요한 것으로..

1. 화면 비율 및 크기 맞추기
2. 디인터레이싱
3. 픽셀 노이즈 제거
4. YV12로 최종 변경처리

 이 정도를 들 수 있겠다. 각각은 제법 중요한 과정이 아닐 수 없는데, 하나하나 간단히 살펴보겠다.

 살펴보기에 앞서, 본인은 AVISynth로 주로 전처리 작업을 하는데, 이것에 대해서는 스스로 알아보기 바란다. 각종 필터들도 많고, 무료에 공개 소프트웨어니 구글에서 조금만 검색하면 어렵지 않게 구할 수 있겠다.



1. 화면 비율 맞추기

 국내 HDTV 방송의 특징은, 와이드가 아닌 4:3의 SD 방송도 16:9로 길~쭉하게 늘려 나온다는 것, 그리고 HDTV 방송에도, 특히 시사 프로그램의 경우, 아날로그 소스가 빈번하게 등장하여 화면 좌우가 검은색으로 나오는 경우도 많다는 것.

 a) 드라마 등의 경우에는 완벽하게 16:9의 와이드 HD방송으로 송출되므로 신경쓸 것 없이 사용.
 b) SD방송의 경우, 16:9의 화면을 4:3으로 적절히 리사이징 하여 사용
 c) 뉴스나 시사 프로그램의 경우 HD방송임에도 불구하고 좌우가 검게 처리되는 4:3 아날로그 영상이 높은 비율로 등장하고, 해당 좌우 부분이 방송되는 순간에도 그 부분을 잘라내더라도 문제가 없는 형태로 방송되는 경우가 많음. 따라서 4:3 Pan&Scan 방식으로 처리해도 문제가 없을 경우 4:3 P&S로 처리하고, 원본 그대로 사용하고 싶은 경우 16:9 와이드 형태 그대로 사용.

 특히 c의 부분에 있어 고민을 조금 하게 되는데, 보기 편하게 만드는 것이 목적이라면 4:3 P&S도 고려해볼만 하다. 의미 없는 부분의 공백을 제거하여 와이드가 아닌 17혹은 19인치 모니터에서도 큰 화면으로 잘 나올 뿐더러, 어쨌든 용량도 절약되니 말이다.

 그리고 화면의 상하좌우 공백을 잘라내는 것도 잊지 말 것. 검은 색으로 테두리가 나오면 인코딩 한 후의 화면도 보기 좋지 않을 뿐더러, 역시 용량도 계속 낭비되니 말이다.

 최종적인 적정한 화면의 크기는.. 디인터레이싱과 함께 나오니 다음으로.



2. 디인터레이싱

 HDTV 소스의 디인터레이싱이야말로 뜨거운 감자가 아닐 수 없다. 많은 사람들이 60fps Bob를 최상으로 친다. 원래의 데이터도 모두 포함할 뿐더러, 인터레이스 상태 그대로 인코딩 하는 것보다는 인코딩 효율이 높기 때문이다. 하지만 이러한 방법은 60fps인 만큼 인코딩 후의 용량도 심히 많이 사용될 뿐더러, 60fps를 재생하기 위한 하드웨어를 갖추어야 한다는 점에서도 여러모로 좋은 방법은 아니다. PMP등의 재생기기에서 재생하는 경우를 상정해도, 60fps Bob은 그다지 매력적인 방법은 아니다.

 HDTV의 소스는 원래 소스 자체가 인터레이스드 60프레임이니 프로그레시브 소스 자체가 존재하질 않으니 원래의 프로그레시브를 맞추어내는 것이 불가능하다.

 개인적으로 (적당한 용량에 적당한 화질의 동영상을 제작하는데 있어서) 추천하는 방법은.. 리사이징을 이용한 블렌딩이다. 1900대x1000대의 동영상을 그대로 인코딩하는 것도 무리이니 이것의 크기를 줄이면서, 디인터레이싱 처리도 하자는 것이다. 결과적으로, 단순히 화면 크기를 반으로 리사이징 하는 것 만으로 홀수라인과 짝수라인이 섞이면서, 900대x500대의 디인터레이싱 된 결과물이 만들어지는 것이다.
 해상도를 반으로 줄이면서, 홀수라인과 짝수라인을 섞어버리면 해상도도 적당해지고, 디인터레이싱도 해결되는 것이다. 움직임이 많은 화면에서도 비교적 자연스러운 움직임을 보여줄테니 의심스러운 분들은 직접 테스트해보시길.
 한가지 문제라면, 하단에 흐르는 자막이 정지 영상에서 두개로 보인다는 점인데.. 그것 빼고는 매우 만족스러운 방법이다.

인터레이스드 NTSC 원본 (200% 확대된 모습)


50% 바이큐빅 리사이즈된 상태. 디인터레이싱 처리는 이렇게 간단히.
(역시 위처럼 200% 확대된 모습)



3. 픽셀 노이즈 제거

 어떤 분들은 '이뭥미?' 하시겠다. '원본 그대로!'를 외쳐대는 많은 분들의 경우 더욱 그러하겠다.

 모든 녹화장비들은 노이즈가 존재한다. 특히나 어두운 곳에서 디카로 사진이나 특히 동영상 촬영을 해보았다면 잘 알 것이다. '자글자글'하다고 하는 바로 그 노이즈가, 조금 어두워보이는 화면에서는 여지 없이 등장한다. 그냥 볼 떄에는 잘 보이지 않지만, 정지화면에서 한스텝씩 넘어가보면 이러한 픽셀단위의 자글거림을 볼 수 있을 것이다. 원본의 외각선과 움직임은 잘 유지하면서, 이러한 노이즈만 제거해내야 하는 것이다.

 이러한 노이즈는 인코딩시에 이러한 노이즈까지 인코딩을 하게 되므로 용량효율이 저하되는데다가, 이러한 노이즈는 움직임이 빠르고 촘촘해서 전체적인 용량대 화질비에 매우 좋지 않은 영향을 끼치게 된다.

 자글자글... 이런 노이즈가 문제.
눈 부릅 뜨고 자세히 보면 잘 보인다.
잘 안보여도 용량은 잡아 먹으니 큰 문제.

 이런 것은 AVISynth의 NoMoSmooth 필터를 이용해서 제거해왔는데, 원본의 날카로움은 잘 유지해주면서 노이즈만 잘 제거해주어 이 밖의 대안을 찾을 이유가 없었다. 다만, 속도가 조금 느린 것은 흠. 이 필터는 YV12 컬러스페이스를 지원하지 않으므로 YUY2로 변경해주어야 한다.



 4. YV12로 최종 변경

 원래 HD방송 소스는 YV12와 같은 형식이라고 보아야 한다. YV12는 YUY2와 비교하면, 눈에 덜 민감한 크로마(chroma, chrominance)채널의 해상도가 반이므로 용량이 더 작다고 보아야 하겠다. 해상도가 반이므로 화질이 더 안좋지 않을까 생각이 들지만, 원래 HD소스부터 해상도가 반인데다가, 크로마 정보가 줄어들었다 해도 체감되는 해상도의 저하는 루마(luma)정보에 더욱 크게 영향을 받으므로, 용량과 화질을 모두 잡고자 한다면 YV12로 최종 결과물을 내는 편이 좋겠다. 따라서 고민하지 말고 YV12로 변경하면서 끝을 내면 되겠다.



5. 최종 AVISynth 작업


 본인은 AVS 파일 내용은 다음처럼 하여 작업하고 있다.

-------------------------------------------------------------

AVISource("HDTV녹화_d2v-vfapi.avi")         : D2V와 VFAPI로 만들어 놓은 AVI를 로드

Crop(16,8,1888,1064)                                    : 검은 공백 부분 잘라내기 (4:3, Wide)
#Crop(248,8,1424,1065)                                : 4:3 Pan & Scan 방식으로 작업

ReduceBy2()                                       : 해상도를 반으로 줄이며 디인터레이싱
#BicubicResize(708,532)                             : Wide 형태로 잘못 송출된 영상의 화면 비율을 4:3으로 바꿀 때 사용

LoadPlugin("C:\Program Files\AviSynth 2.5\plugins\NoMoSmooth.dll")
ConvertToYUY2()
                                         : NoMoSmooth() 필터가 YUY2 컬러스페이스를 요구하기 때문에 변경
NoMoSmooth()                                             : 기본값으로 노이즈 제거

ConvertToYV12()                                          : 최종적으로 YV12로 변환

-----------------------------------------------

 여타 코덱등의 선택은 유저들의 몫이 되겠다. 그럼 즐거운 인코딩 생활 되시길~! :)


by openwrld | 2008/05/11 18:48 | 트랙백 | 덧글(5)

양력을 음력으로 변환하는 C 코드..

양력을 음력으로 바꾸는 기능만을 가진, 가장 간결하고 튼튼한 코드를 찾다가..
인터넷에서 찾아낸 코드들이 너무도 구구절절(...)하여 직접 작업하기로 함.

계산 방법은 간단하더라고. 특정일부터 며칠 지났는지 양력으로 계산하고, 다시 그 지난 수만큼 음력으로 세어 오는.. 그다지 스마트하지는 않아 보이는 방법이 유일하다더구만.


암튼.. 이 코드는 다른 기능은 없고, 2001년 2월 이후의 [양력->음력] 기능만 동작함. 그 이전은 필요 없겠지?
long 타입도 없고 16bit int 정도면 잘 동작하리라고 봄..  2050년까지라고 해도 20000일을 넘지 않으니 int로 일단 충분.

음력 2001년 01월 01일 기준으로 세어서 동작하도록 해놓았음.



그럼 사용법..

int resut[3];
getLunarDate( getTotalDaySolar( 양력 년, 양력 월,양력 일 ), result );

이렇게 하면.. result[]에 {음력 년, 음력 월, 음력 일}이 차례로 들어감.


** 주의할 점.. 연도는 2자리로만 넣어야 함. **
** ex> 2001년 표기는 01로 넣어야 하고 역시 01로 나오면 2001년 됨. **





int lunarDayOfMonth[] = {29,30,58,59,59,60};

int lunarDayOfMonthFrac[] = {0,0,29,30,30};

char lunarDayOfMonthIndex[][12] = {
    // 2001 ~ 2010
    {1,1,1,2,1,0,0,1,0,1,0,1},{1,1,0,1,0,1,0,0,1,0,1,0},
    {1,1,0,1,1,0,1,0,0,1,0,1},{0,4,1,1,0,1,0,1,0,1,0,1},
    {0,1,0,1,0,1,1,0,1,1,0,0},{1,0,1,0,1,0,4,1,1,0,1,1},
    {0,0,1,0,0,1,0,1,1,1,0,1},{1,0,0,1,0,0,1,0,1,1,0,1},
    {1,1,0,0,4,0,1,0,1,0,1,1},{1,0,1,0,1,0,0,1,0,1,0,1},
    // 2011 ~ 2020
    {1,0,1,1,0,1,0,0,1,0,1,0},{1,0,5,1,0,1,0,0,1,0,1,0},
    {1,0,1,1,0,1,0,1,0,1,0,1},{0,1,0,1,0,1,0,1,4,1,0,1},
    {0,1,0,0,1,0,1,1,1,0,1,1},{0,0,1,0,0,1,0,1,1,0,1,1},
    {1,0,0,1,2,1,0,1,0,1,1,1},{0,1,0,1,0,0,1,0,1,0,1,1},
    {1,0,1,0,1,0,0,1,0,1,0,1},{1,0,1,4,1,0,0,1,0,1,0,1},
    // 2021 ~ 2030
    {0,1,1,0,1,0,1,0,1,0,1,0},{1,0,1,0,1,1,0,1,0,1,0,1},
    {0,4,1,0,1,0,1,1,0,1,0,1},{0,1,0,0,1,0,1,1,0,1,1,0},
    {1,0,1,0,0,4,1,0,1,1,1,0},{1,0,1,0,0,1,0,1,0,1,1,1},
    {0,1,0,1,0,0,1,0,0,1,1,1},{0,1,1,0,4,0,1,0,0,1,1,0},
    {1,1,0,1,1,0,0,1,0,0,1,1},{0,1,0,1,1,0,1,0,1,0,1,0},
    // 2031 ~ 2040
    {1,0,4,1,0,1,1,0,1,0,1,0},{1,0,0,1,0,1,1,0,1,1,0,1},
    {0,1,0,0,1,0,4,1,1,1,0,1},{0,1,0,0,1,0,1,0,1,1,1,0},
    {1,0,1,0,0,1,0,0,1,1,0,1},{1,1,0,1,0,3,0,0,1,0,1,1},
    {1,1,0,1,0,0,1,0,0,1,0,1},{1,1,0,1,0,1,0,1,0,0,1,0},
    {1,1,0,1,4,1,0,1,0,1,0,0},{1,0,1,1,0,1,1,0,1,0,1,0},
    // 2041 ~ 2050
    {1,0,0,1,0,1,1,0,1,1,0,1},{0,4,0,1,0,1,0,1,1,0,1,1},
    {0,1,0,0,1,0,0,1,1,0,1,1},{1,0,1,0,0,1,2,1,0,1,1,1},
    {1,0,1,0,0,1,0,0,1,0,1,1},{1,0,1,1,0,0,1,0,0,1,0,1},
    {1,0,1,1,3,0,1,0,0,1,0,1},{0,1,1,0,1,1,0,1,0,0,0,0},
    {1,0,1,0,1,1,0,1,1,0,1,0},{1,0,3,0,1,0,1,1,0,1,1,0}
};

int lunarDayOfYear[] = {
    384,354,355,384,354,385,354,354,384,354,    // 2001 ~ 2010
    354,384,355,384,355,354,384,354,354,384,    // 2011 ~ 2020
    354,355,384,354,384,355,354,383,355,354,    // 2021 ~ 2030
    384,355,384,354,354,384,354,354,384,355,    // 2031 ~ 2040
    355,384,354,384,354,354,384,353,355,384     // 2041 ~ 2050
};

char solarDayNum[] = {31,28,31,30,31,30,31,31,30,31,30,31};

int getSolarDayOfMonth(int y, int m){    // 월별 일수 계산
    if (m!=2) return solarDayNum[m-1];
   
    if ( (y%400==0) || ((y%100 != 0) && (y%4 ==0)) ) return 29;
    else return 28;
}

int getSolarDayOfYear(int y){
    if ( (y%400==0) || ((y%100 != 0) && (y%4 ==0)) ) return 366;
    else return 365;
}

// 양력 2001/01/24 = 음력 2001/01/01
char solarBasis[] = { 1, 1,24};

int getTotalDaySolar(char y, char m, char d){
    int i, ret = 0;
   
    for (i = solarBasis[0]; i<y; i++) ret += getSolarDayOfYear(i);
    for (i = 1; i<m; i++) ret += getSolarDayOfMonth(y,i);
    ret+=d;
    for (i = 1; i<solarBasis[1]; i++) ret -= getSolarDayOfMonth(solarBasis[0],i);
    ret-=solarBasis[2];

    return ret;
}

void getLunarDate(int totalDay, char* result){    // result[0]~[2] 에 넣음
    int y = -1, m = -1, d = 0, f;
   
    while(totalDay >= lunarDayOfYear[++y]) totalDay -= lunarDayOfYear[y];
    while(totalDay >= (d = lunarDayOfMonth[lunarDayOfMonthIndex[y][++m]]))
        totalDay -= d;
    d = totalDay;
   
    f = lunarDayOfMonthFrac[lunarDayOfMonthIndex[y][m]];
    if (d>=f) d -= f;
   
    result[0] = y+1; result[1] = m+1; result[2] = d+1;
}

by openwrld | 2007/08/19 23:27 | Java/C | 트랙백 | 덧글(1)

HMM3 (Heroes of Might and Magic 3) 자기 자신과 싸우는 버그..

 이런 말도 안되는 버그가.. ㅋㅋ

 아까 타이탄 36마리 가량 모아서 쓸고 다니다가 발견한 건데.. 전투 시작하고 보니 적 한테도 타이탄이 36마리나 있길래 -_- 캐릭 찍어보니 상대 영웅도 내 영웅 캐릭.. -_-;; (위 캡춰는 겜 일단 끝내고 다른 세이브 불러서 버그 재현한 것임..)

 마나는 1000을 넘고 타이탄 36마리.. 아.. alt+f4 누르고 autosave 파일 부를까.. -_- 하다가 경험치나 올리자고 생각해서 공성전 들어감.. 결국 마법과 유닛 활용-_-의 승리로 내 타이탄만 20마리 가량 남고 모든 유닛 전멸.. 그러고 나니 컴터가 에어엘리멘탈을 끝없이 소환하기 시작함.. -_-;; 마나가 1000이 넘으니 지겨울 정도로 소환하더군.. 나는 거기에 어스엘리멘탈로 대응..

 자신과의 싸움에서 결국 승리.. -_- 아이템 쏟아지고.. 아.. 경치 얼마나 오르나 볼까..하고 있는데 캐릭이 스윽~ 사라지더구만. 공성전은 승리로 처리되는데.. 캐릭은 진 것으로 되어서-_- 아이템 무더기로 가진 내 메인캐릭이... -_-

 결국 autosave 불러왔지. ㅡ_ㅡ


 암튼.. 이 버그는 우연히 발견한건데..

1. Fly 마법을 익힌다. (혹은 날개(?) 아이템을 구한다)
2. 적이 점령하고 있는 성의 성문 위를 지나는 방향으로 경로를 찍는다.
3. M키를 눌러 이동을 시작
4. 이동하는 도중, 성문 위를 지나는 순간 마우스 오른쪽 버튼을 클릭하여 정확히 성문 위에서 멈춘다 -_-;
  (이게 포인트.. 상대편 성문에서 garrison 상태에 있는 것 처럼 멈추어야 함)
5. 스페이스바를 눌러 전투를 시작함.. (전투는 시작되는데.. 성문 위에 겹친 영웅이 garrison 된 것으로 인식하는 모양)

 빈 성만 되는지.. 아니면 영웅이 존재하는 성도 되는지는 모르겠음..


 암튼.. 골때리는 버그-_-;

by openwrld | 2007/08/09 22:06 | 게임 | 트랙백 | 덧글(2)

컴퓨터의 파워서플라이 (PSU)

 아. 요새는 효율 얘기만 들으면 손이 근질근질 하다. 최적화 하는 삽질에는 자신 있다는 건가? 어찌되었든 재미 있어 보인다. (뭐.. DSP 프로그래밍 할 때에도 코드 효율에 있어서는 상당히 자신이 있었으니까. 실행속도나 코드 사이즈 최적화에 있어서는 그래도 어디 가서도 명함 정도는 내밀 수 있지 않을까.. -_-;; x86에 와서는 뭐 전혀 아니겠지만. ) 삽질을 한지가 제법 된지라 금단증상이 오나보다. 파워 만드는 작은 회사에서 알바라도 뛸까.. -_-;

 엄청나게 많이 출시된 파워 서플라이들. 별다른 데이터도 없이, 파는 애들-_-이 제공하는 스펙들을 믿고 구입해야 된다. 어떤 파워가 얼마나 더 시끄러운지, 효율이 얼마나 높은지, 전압은 안정적으로 들어가는지, 서지 따위에 대한 대책은 얼마나 되어 있는지 등. 선전 문구로 보면 싸구려 파워들도 고효율에 조용하고 안정적이라고 광고하는데. 믿을 수 있을까나.
 결국 대부분의 경우, 브랜드 네임에 의지하거나, 무난한 제품을 고르기 위해 이미 많이 판매되는 제품을 다시 고르는 소비자들이 많아지는 거다.

 또한.. 국내 대부분의 리뷰어들의 경우.. 파워 서플라이를 제대로 평가할만한 지식과 장비가 없다. (확신한다!) 대부분의 그 사람들은 컴퓨터가 좋아서 컴퓨터 관련 부품 리뷰를 하고 있을 뿐이지. 파워들 비교한답시고 기껏 해야 뚜껑 열어서 컨덴서에 적힌 소자값과 메이커 정도 확인하고 사진 찍어 올리는게 대부분이지. (대충 오디오 쪽이랑 비슷하다...)

 조금 다른 얘기지만. 펜티엄3부터 펜티엄4의 노스우드, 프레스캇, 시더밀, 펜티엄D, 코어2듀오, 코어2쿼드로 넘어오면서 CPU의 전력 소모량은 크게 변해왔다. CPU만 봐서는 자릿수가 차이가 날 정도니까. IDLE 상태의 전력 소모마저도 상당히 차이가 나고. GPU도 천차 만별이고. 보통 PC 1대가 소비하는 전력이 얼마쯤 되는지 제대로 알고 있는 사람이 얼마나 될까나. 파워 용량 계산기라도 돌아다니는 그 계산기의 값과 실제 사용량의 괴리는 상당하다. 요새 조립하는 왠만한 개인용 PC는 100~150와트 정도 사용할 게다. VGA가 조금 변수이긴 한데. 게임용 GPU 없고 오버클럭 안한 PC는 최악의 경우로 풀로드 걸어도 200와트 안 넘을 게다.. 하지만 파워는 350~400와트짜리 다들 권하잖아. (사실.. 350와트짜리 파워가 300와트 넘어서도 잘 동작하는지는 모르겠어. 라인마다 최대출력이 따로따로이기도 하지만 제대로 부하 걸어줘도 얼마나 버틸진 모르지. 쏟아져 나오는 저가 파워들을 믿을 수가 없다는 거다.)
 어쨌든 왠만해서는 자기 PC가 얼마나 전력을 사용하고 있는지도 모르는 사람들이 파워서플라이 리뷰도 쓰고 뭐 그런다는거지.



 각설하고.


 PSU에 대한 폭넓은 테스트를 진행하기 위해서는 이런 저런 장비들이 필요하다. 서지나 스웰, 새그 입력 테스트를 하기 위한, 파형을 마음대로 넣을 수 있는 인버터도 필요할 것이고. 정밀한 AC 전력 측정기도 필요할 것이고. 다채널의 DC 부하 장비도 필요할 것이고. 제법 정밀한 오실로스코프도 필요할 것이고. 소음 측정장비도 필요할게다. 역률 측정하고 싶으면 그것도 필요할게고. (테스트용 인버터에는 왠만큼은 이런 저런 수치가 나오긴 하지만서도.)

 허나 개인 입장에서 저런 것들을 다 갖출 수 있겠나? 다 빌리기도 만만찮을 것이고. 테스트 조건과 항목들을 정하는 것도 만만치 않을거다. 장비들 다 구해다 줘도 할 수 있는 사람도 그다지 많지 않을게고. 이런 장비 다 갖추고 있고 능력까지도 있는 사람들은 푼돈-_-에 노가다 하고 싶진 않겠지.



파워 인증해주는 벤처기업이라도 하나 누가 차리지. 답답해서 파워 못 고르겠다고.

(다른건 안하더라도 효율 테스트는 다~ 한번씩 해서 표로 좀 정리했으면 좋겠다. 이거 뭐 아무 파워나 다 고효율이라고 광고하니.)

by openwrld | 2007/07/08 02:33 | 트랙백 | 덧글(1)

◀ 이전 페이지          다음 페이지 ▶