Android 그림 처리(Matrix, ColorMatrix)

해가 쌓이고 달이 쌓인 다음주 셋째 날.평범한 하루, 출근길, 출근길, 식사, 퇴근길, 막연해...
프로그래밍에서 때때로 그림에 대해 특수한 처리를 해야 한다. 예를 들어 그림을 흑백으로 만들거나 오래된 사진의 효과, 때로는 그림을 바꾸어 스트레칭, 비틀기 등이다.
이러한 효과는android에서 매우 잘 지원되며, 색 매트릭스 (ColorMatrix) 와 좌표 변환 매트릭스 (Matrix) 를 통해 위에서 말한 효과를 완벽하게 나타낼 수 있다.
다음은 이 두 행렬의 용법과 관련된 함수를 각각 소개할 것이다.
색 행렬
안드로이드에서는 색 매트릭스 (ColorMatrix 클래스) 를 통해 색을 조작할 수 있으며 색 매트릭스는 5x4 매트릭스입니다 (그림 1.1 참조)
그림에서 RGBA의 각 컴포넌트의 값을 수정할 수 있으며 색상 행렬은 1차원 배열로 다음과 같이 저장됩니다.
 [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]
그는 RGBA 네 개의 채널을 통해 대응하는 색을 직접 조작한다. 포토샵을 사용하면 그림을 처리할 때 RGBA의 각 색 채널을 제어함으로써 특수한 효과를 낼 수 있다는 것을 알 수 있다.
이 행렬의 색상 동작은 1.3과 같이 계산됩니다.
행렬의 연산 규칙은 행렬 A의 한 줄에 행렬 C의 한 열을 곱하여 행렬 R의 한 줄로 하는 것이다.
C 매트릭스는 그림에 포함된 ARGB 정보이고, R 매트릭스는 C 다음에 색상 매트릭스로 적용되는 새로운 색상 컴포넌트로 연산 결과는 다음과 같습니다.
 
R' = a*R + b*G + c*B + d*A + e;
G' = f*R + g*G + h*B + i*A + j;
B' = k*R + l*G + m*B + n*A + o;
A' = p*R + q*G + r*B + s*A + t;
 
색 행렬은 보기에는 그렇게 심오해 보이지 않지만, 사실 필요한 매개 변수는 매우 적고, 규칙적으로 첫 번째 줄이 빨간색을 결정하고, 두 번째 줄이 녹색을 결정한다.
세 번째 줄은 파란색을 결정하고, 네 번째 줄은 투명도를 결정하며, 다섯 번째 열은 색의 편이도이다.다음은 실제 사용되는 색 행렬입니다.
이 행렬을 각 색의 분량에 작용하면 R=A*C를 계산한 결과 각 색의 분량은 사실상 아무런 변화가 없다는 것을 알 수 있다(R'=R G'=G B'=B A'=A).
그림1.5에서 보여준 행렬을 계산하면 빨간색 분량은 100, 녹색 분량은 100,
이런 효과는 바로 그림이 노랗게 변하는 것이다. 빨간색과 녹색을 혼합한 후 노란색을 얻었기 때문에 노란색이 100 증가했기 때문에 그림은 당연히 노랗게 변한다.
색상 컴포넌트를 변경하면 5열의 색상 오프셋을 수정할 뿐만 아니라 위 행렬에 표시된 대로 해당 색상 값을 배수로 곱하여 직접 확대할 수 있습니다.
위의 그림 1.6은 녹색 분량을 2에 곱하여 원래의 2배로 바꾸는 것이다.독자들은 이로써 어떻게 색 행렬을 통해 각 색의 분량을 바꾸는지 알게 될 것이라고 믿는다.
다음은 JavaCode가 색상 매트릭스를 조정하여 다양한 색상 효과를 얻을 수 있도록 코드를 작성합니다.
CMatrix :  
 public class CMatrix extends Activity {  
      
    private Button change;  
    private EditText [] et=new EditText[20];  
    private float []carray=new float[20];  
    private MyImage sv;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
          
       change=(Button)findViewById(R.id.set);  
       sv=(MyImage)findViewById(R.id.MyImage);  
      
       for(int i=0;i<20;i++){  
            
       et[i]=(EditText)findViewById(R.id.indexa+i);  
       carray[i]=Float.valueOf(et[i].getText().toString());  
       }  
          
       change.setOnClickListener(l);  
    }  
      
    private Button.OnClickListener l=new Button.OnClickListener(){  
   
       @Override  
       public void onClick(View arg0) {  
           // TODO Auto-generated method stub  
            getValues();  
           sv.setValues(carray);  
           sv.invalidate();  
       }  
          
    };  
    public   void getValues(){  
        for(int i=0;i<20;i++){  
              
            carray[i]=Float.valueOf(et[i].getText().toString());  
        }  
          
    }  
   
      
}  
MyImage    View :  
public class MyImage extends View {  
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
    private Bitmap mBitmap;  
    private float [] array=new float[20];  
      
    private float mAngle;  
      
    public MyImage(Context context,AttributeSet attrs) {  
        super(context,attrs);  
          
        mBitmap    = BitmapFactory.decodeResource(context.getResources(),  
                                               R.drawable.test);  
        invalidate();  
    }  
     
      
    public void setValues(float [] a){  
        for(int i=0;i<20;i++){  
           array[i]=a[i];  
        }  
          
    }  
      
    @Override protected void onDraw(Canvas canvas) {  
        Paint paint = mPaint;  
          
          
          
        paint.setColorFilter(null);  
        canvas.drawBitmap(mBitmap, 0, 0, paint);  
          
        ColorMatrix cm = new ColorMatrix();  
       //        
       cm.set(array);  
//    ,            
        paint.setColorFilter(new ColorMatrixColorFilter(cm));  
//    
        canvas.drawBitmap(mBitmap, 0, 0, paint);  
        Log.i("CMatrix", "--------->onDraw");  
   
         
    }  
     
}

Cmatrix 클래스는 주로 색상 매트릭스의 설정을 수신하고 다시 그리는 것을 책임지며 할 말이 없습니다.MyImage 클래스에서 드로잉 작업을 수행하려면 먼저 색상 행렬 cm를 설정합니다.set(..)1차원 그룹에서 20개의 데이터를 읽어서 색 행렬에 값을 부여합니다.paint.setColorFilter(..)색 필터를 설정한 다음에 그림을 그리면 효과가 나온다(이 과정은 PS와 차이가 많지 않다)는 것은 다음과 같다. 여기를 보면 색 행렬의 작용에 대해 직관적인 느낌을 받았을 거라고 믿고 지금도 사진 효과 소프트웨어를 만들어 볼 수 있다.
그러나 각종 효과는 사용자가 수동으로 색 행렬을 조절하게 할 수 없다. 여기에 계산 공식이 필요하다. 본인이 도형 소프트웨어를 하는 사람이 아니기 때문에 제공할 수 없기 때문에 이 링크를 참고할 수 있다.http://www.adobe.com/devnet/flash/articles/matrix_transformations/ColorMatrixDemo.swf
좌표 변환 매트릭스 좌표 변환 매트릭스는 3*3의 매트릭스로 그림2.1과 같이 도형에 대해 좌표 변화를 하고 원래의 좌표점을 새로운 좌표점으로 옮긴다.
하나의 그림은 점진과 각 점의 색 정보로 구성되어 있기 때문에 좌표에 대한 변환은 각 점을 옮겨 새로운 그림을 형성하는 것이다.
구체적으로 말하면 도형의 확대, 축소, 이동, 회전, 투시, 비틀기 등 효과는 모두 이 행렬로 완성할 수 있다.이 행렬의 작용은 좌표 x, y를 변환하여 계산한 결과 다음과 같다. x'=a*x+b*y+c y'=d*x+e*y+f 일반적인 상황에서 g=h=0, 이렇게 하면 1=0*x+0*y+1이 항상 성립된다.색 매트릭스와 마찬가지로 좌표 변환 매트릭스에서 실제로 사용하는 매개 변수는 매우 적고 규칙적이다.위의 그림은 좌표 변환 행렬의 간단한 예로 계산한 후에 x'=x+50, y'=y+50을 발견했다.
그림의 모든 점이 x와 y방향에서 (50, 50)점으로 옮겨진 것을 알 수 있다. 이런 효과는 바로 옮겨진 효과로 그림을 (50, 50)점으로 옮긴 것이다.위의 행렬을 계산하는 x'=2*x, y'=2*y. 색 행렬과 위의 이동 효과 학습을 통해 독자들이 이 행렬의 작용을 이해할 수 있을 것이라고 믿는다. 이 행렬은 그림을 확대했는데 구체적으로 말하면 두 배로 확대되었다.다음은 몇 가지 자주 사용하는 변환 행렬을 소개할 것이다.빙글빙글 돌다
원점 반시계 방향으로 회전θ도각의 변환 공식은 x'= xcosθ − ysinθ y. '=xsinθ +    ycosθ 2. 배율 조정
변환 후 길이와 폭을 각각 x'=scale*x로 확대;y'=scale*y. 3.절변
4. 반사(,) 단위 벡터 5.정투영(,) 단위 벡터 위의 각종 효과도 함께 중첩할 수 있다. 행렬의 조합 변환은 행렬 곱셈으로 실현할 수 있다. 예를 들어 R=B(A*C)=(B*A)C이다. 주의해야 할 것은 B*A와 A*B는 일반적으로 같지 않다는 것이다.
다음은 다음과 같이 좌표 변환 행렬을 제어하여 도면을 제어하는 애플릿입니다.
CooMatrix :  
  
 3public class CooMatrix extends Activity {  
     
   private Button change;  
   private EditText [] et=new EditText[9];  
   private float []carray=new float[9];  
   private MyImage sv;  
   /** Called when the activity is first created. */  
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
       super.onCreate(savedInstanceState);  
       setContentView(R.layout.main);  
         
      change=(Button)findViewById(R.id.set);  
      sv=(MyImage)findViewById(R.id.MyImage);  
       
      for(int i=0;i<9;i++){  
           
      et[i]=(EditText)findViewById(R.id.indexa+i);  
      carray[i]=Float.valueOf(et[i].getText().toString());  
        
      }  
         
     change.setOnClickListener(l);  
         
       
   }  
     
   private Button.OnClickListener l=new Button.OnClickListener(){  
  
      @Override  
      public void onClick(View arg0) {  
          // TODO Auto-generated method stub  
          getValues();  
          sv.setValues(carray);  
          sv.invalidate();  
      }  
         
   };  
   public   void getValues(){  
       for(int i=0;i<9;i++){  
             
           carray[i]=Float.valueOf(et[i].getText().toString());  
       }  
         
   }  
  
     
50}  
51MyImage    View :  
52public class MyImage extends View {  
   private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
   private Bitmap mBitmap;  
   private float [] array=new float[9];  
     
     
     
   public MyImage(Context context,AttributeSet attrs) {  
       super(context,attrs);  
         
       mBitmap = BitmapFactory.decodeResource(context.getResources(),  
                                              R.drawable.ic_launcher_android);  
       invalidate();  
   }  
    
     
   public void setValues(float [] a){  
       for(int i=0;i<9;i++){  
          array[i]=a[i];  
       }  
         
   }  
     
   @Override protected void onDraw(Canvas canvas) {  
       Paint paint = mPaint;  
       canvas.drawBitmap(mBitmap, 0, 0, paint);  
       //new           
       Matrix cm = new Matrix();  
80//               
      cm.setValues(array);  
82//               
       canvas.drawBitmap(mBitmap, cm, paint);  
       Log.i("CMatrix", "--------->onDraw");  
  
        
   }

위의 코드에서 클래스 CooMatrix는 사용자가 입력한 좌표 변환 매트릭스 매개 변수를 수신하는 데 사용되며, 클래스 MyImage 수신 매개 변수는 setValues()를 통해 매트릭스 매개 변수를 설정하고 Canvas에서 drawBitmap 드로잉을 호출합니다.효과는 다음과 같습니다.
위에서 좌표 변환 매트릭스로 이루어진 여러 가지 효과, 좌표 변환 매트릭스로 도형을 조절할 수 있는 여러 가지 효과,
그러나 Matrix 클래스를 보면 알 수 있듯이 실제로 Matrix 클래스 자체는 이미 많은 유사한 방법을 제공했고 우리는 호출하기만 하면 된다.setScale(float sx,float sy,float px,float py) 확대 setSkew(float kx,float ky,float px,float py) 슬라이드 setTranslate(float dx,float dy) 슬라이드 setRotate(floate,float px,float py,float py) 회전 위의 함수는 기본적인 변환, 확대, 회전, 슬라이드 기능을 제공합니다.더 복잡한 변환을 하기 위해 좌표 변환 행렬을 직접 바꾸지 않아도 되고,
Matrix 클래스는 원래 그래픽을 타겟 점에 매핑하여 새 그래픽을 구성하는 여러 맵 방법을 제공합니다.
다음은 setPolyToPoly(float[]src, intsrcIndex,float[]dst, intdstIndex, intpointCount)의 사용법을 약술하고 일거수일투족의 역할을 하고자 합니다.
매개 변수 src와 dst는 원 이미지의 점과 지정한 목표점을 각각 저장한 1차원 그룹입니다. 그룹에 저장된 좌표 형식은 다음과 같습니다. [x0, y0, x1, y1, x2, y2,...]이 함수는 src의 좌표를 dst의 좌표에 비추어 그림의 변환을 실현합니다.
구체적인 예는 APIDemos의 Poly ToPoly를 참고할 수 있습니다. 저는 여기서 코드를 붙이지 않고 함수가 어떻게 그림을 바꾸는지 설명합니다.다음은 효과: 그림에서 1은 원도이고, 2, 3, 4는 변환된 도형이다.현재 분석2는 어떻게 변환되었는지, 변환된 원 좌표점과 목적 좌표점은 다음과 같다. src=new float[] {32, 64, 32} dst=new float[] {32, 32, 64, 48} 위의 아이콘에서 보여준 좌표에서 원도를 보인(32,32) 원도에 비친(32,32)(64,32) 원도에 비친(64,32) 효과는 이미지가 확대되고 회전되었다.이러한 프로세스는 (32, 32)점에서 움직이지 않고 그래프(64, 32)점을 잡아당겨 (64, 48)점까지 잡아당기면 그래프가 확대되고 회전할 수밖에 없는 것과 같습니다.마지막으로 변환을 사용하여 그래프를 오른쪽의 현재 위치로 이동합니다.이 과정을 잘 이해해 주시기 바랍니다. 아래의 3, 4 그림은 같은 이치입니다.

좋은 웹페이지 즐겨찾기