기본 콘텐츠로 건너뛰기

추천 가젯

[프로그래밍 이야기 6] 포터블 라이터기의 재발견: 웹소켓과 스크립트가 만든 현장 대응 파이프라인

 임베디드 장비나 FPGA 칩이 탑재된 하드웨어를 현장에서 다룰 때, 가장 고민스러운 부분은 펌웨어 라이팅 환경을 구축하는 일입니다. 공장 PC나 현장 컴퓨터에 무겁고 거대한 벤더 전용 프로그램(IDE)을 일일이 설치하고 환경을 설정하는 것은 지극히 비효율적입니다. 이때 가장 똑똑하고 유연한 접근법은 공장 PC에 무언가를 설치하려 애쓰는 대신, 엔지니어의 노트북 한 대를 즉시 '포터블(Portable) 라이터기'로 탈바꿈시켜 현장에 투입하는 것입니다. 노트북을 포터블 라이터기로 만드는 전략과 웹소켓 노트북을 이동식 포터블 라이터기로 활용하기 위해 거창한 프로그램을 깔 필요는 전혀 없습니다. 핵심은 펌웨어를 입히는 CLI(명령줄 인터페이스) 툴과, 이를 원격에서 실행해 줄 지극히 단순하고 가벼운 웹소켓(WebSocket) 서버 하나만 준비하는 것입니다. 중요한 점은 여기서 사용하는 웹소켓 프로그램이라는 것이 결코 복잡하거나 무거운 시스템이 아니라는 사실입니다. 단 몇 킬로바이트 수준의 경량 훅(Hook) 역할만 수행하는 웹소켓 서버를 노트북에 띄워두면, 공장 PC 환경을 오염시키지 않고도 노트북 한 대가 완벽한 이동식 라이팅 단말기로 변신합니다. 가장 가벼운 웹소켓 훅과 Shell 스크립트의 결합 이 시스템의 실체는 놀라울 정도로 가볍고 명확합니다. 노트북 내부에서는 하드웨어(.sof)를 구운 뒤 MCU 펌웨어(.elf)를 연달아 다운로드하는 아래의 Shell 스크립트가 실행의 중심을 잡습니다. // flasher.sh - FPGA 및 Nios II 펌웨어 연속 라이팅 스크립트 #!/bin/bash 1. FPGA Hardware (.sof) 구우기 #!/bin/bash echo "Hello World" echo "=== Programming FPGA Hardware ===" quartus_pgm -c "USB-Blaster [1-4]" -m JTAG -o "p;mcu.sof...

한눈에 보는 Blending mode 색섞기. (on GIMP)



Top Layer


Bottom Layer


일단 다음처럼 두개의 레이어를 만들고, 여러 효과를 넣어본다.
편의상 여기서는 integer 8bit 로만 나타내며 0-255로 표현한다.
gimp 최신버전 코드를 깟는데 float로 계산한다.

가장 많이 쓰는 Screen 과 overlay 그리고 Multiply(곱)
Screen
Overlay

Multiply












in이 top이고 layer가 바닥이다. 
comp[c] = in[c] * layer[c];

0-1값으로 생각하면 쉽게 어두워짐을 알 수 있다.  이 다음부터는 그림만가지고 이야기한다.

그림은 많이 쓰이는 순서이지만 설명은 Multiply부터 하는 것이 쉽다.



comp[c] = 1.0f - (1.0f - in[c]) * (1.0f - layer[c]);
Screen은 반전 후 곱한 색상을 반전하는 것과 같다.  반대로 좀 더 밝아 짐을 볼 수 있다.


Overlay부터는 top layer와 bottom layer가 서로 동등하지 않다. 일단 normal모드 부터 동등하지 않으므로 이상한 것은 아니다.
if (in[c] < 0.5f)
      val = 2.0f * in[c] * layer[c];
else
     val = 1.0f - 2.0f * (1.0f - layer[c]) * (1.0f - in[c]);
무언가 복잡하다.  Screen과 Multiplay의 중간 느낌이다.
아직 메뉴얼은 그대로지만 photoshop으로 대동단결 했다.
Hard light에서 복사해오자.

Top Layer를 흰색에서 회색, 회색에서 검정 두부분으로 나누어,  어두운곳은 Multiply효과를  밝은 곳은 Screen효과를 준다. 
중간영역의 대비가 커진다. 그 결과 색상이 강해지고, 경계가 날카로와 진다.


다음은 LightenOnly와 DarkenOnly이다.
각값에서 밝은 값과 어두운 값을 취한다.
comp[c] = MAX (in[c], layer[c]);
comp[c] = MIN (in[c], layer[c]);






















다음은 Burn과 Dodge이다.

Dodge
   256 x B / { (255-T} +1 }
comp[c] = safe_div (in[c], 1.0f - layer[c]);


Burn
255- 256x (255-B)/{ T+1}
comp[c] = 1.0f - safe_div (1.0f - in[c], layer[c]);
Dodge의 반대로 작용한다.

Linear burn
그냥 덧셈이다. clipping이 될 수 있다. 
            comp[c] = in[c] + layer[c] - 1.0f;


다음은 조명 계통이다.  
Hard light, soft light, vivid light pin light 등이다. 

Hard light
 255 - (255-2(T-128)) x (255-B) /256   if T > 128
  2 x T x B                                             if T <=128

Top Layer를 흰색에서 회색, 회색에서 검정 두부분으로 나누어,  어두운곳은 Multiply효과를  밝은 곳은 Screen효과를 준다. 
중간영역의 대비가 커진다. 그 결과 색상이 강해지고, 경계가 날카로와 진다.
 if (layer[c] > 0.5f)
{
     val = (1.0f - in[c]) * (1.0f - (layer[c] - 0.5f) * 2.0f);
     val = MIN (1.0f - val, 1.0f);
 }
 else
{
      val = in[c] * (layer[c] * 2.0f);
      val = MIN (val, 1.0f);
}
 Overlay와 동등한 식이지만, 기준이 bottom layer이다. in <-->layer를 하면, 같다. xy축을 바꾸면 바로 알 수 있다. 
Soft light
이름과 달리 Hard light와는 별관련이 없다.  Screen Mode와 매우 유사하다.

멏몇 버전의 GIMP에서는 Screen과 같다. ( 계속 다시 옜날로 가는 경우가 있나보다. )

스크린된 Pixel을 S라고 하자. 

S= 255 - (255-T) x (255-B) / 255

{  (255-B)xT + S} x B / 255   이다. 다만 홈페이지에 오류가 있는 것으로 보인다. 앞항도 255로 나누어야한다. 

무언가 식만 보고 이해하기는 어렵다. 그리고 제대로 적용될지 확신할 수 없기에 쓰면 안될 것으로 보인다. 나머지는 gimp의 코드를 까봐야할 것 같다. 
일단 여기까지 작성하자. 

gfloat multiply = in[c] * layer[c];
gfloat screen   = 1.0f - (1.0f - in[c]) * (1.0f - layer[c]);
gfloat val      = (1.0f - in[c]) * multiply + in[c] * screen;

상위 픽셀에 따라, multiply와 screen을 얼마나 섞을지 정한다. 


Vivid light
if (layer[c] <= 0.5f)
{
     val = 1.0f - safe_div (1.0f - in[c], 2.0f * layer[c]);
     val = MAX (val, 0.0f);
}
else
{
     val = safe_div (in[c], 2.0f * (1.0f - layer[c]));
     val = MIN (val, 1.0f);
}

Overlay처럼 구간을 나누어, dodge와 burn을 적용한다.

Pin light

이것은 lighten과 darken을 조합하는 것 같다.
 if (layer[c] > 0.5f)
                val = MAX(in[c], 2.0f * (layer[c] - 0.5f));
              else
                val = MIN(in[c], 2.0f * layer[c]);



Linear light

if (layer[c] <= 0.5f)
     val = in[c] + 2.0f * layer[c] - 1.0f;
else
     val = in[c] + 2.0f * (layer[c] - 0.5f);
그렇다.




더하기 .

comp[c] = in[c] + layer[c];






빼기, 차이 






댓글