0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claudeに簡単な画像処理について質問

0
Last updated at Posted at 2026-07-05

Claudeに簡単な画像処理をきいてみた

画像処理の話をするとBayer,RGB,YUVといった話がよく出る.
これらについて一般的なJPEGになるまでの処理をClaudeに聞いてコードを生成した.

#include <stdint.h>

#define WIDTH  1920
#define HEIGHT 1080

static uint8_t clamp_u8( int val )
{
  if( val<0 ) {
    return 0;
  } else if( val>255 ) {
    return 255;
  } else {
    return (uint8_t)val;
  }
}

static uint8_t get_pixel( const uint8_t bayer[HEIGHT][WIDTH], int row, int col )
{
  if( row<0 ) {
    row = 0;
  }
  if( row>=HEIGHT ) {
    row = HEIGHT - 1;
  }
  if( col<0 ) {
    col = 0;
  }
  if( col>=WIDTH ) {
    col = WIDTH - 1;
  }
  return bayer[row][col];
}

/* RGGBパターン想定 */
void bayer_to_rgb(
  const uint8_t bayer[HEIGHT][WIDTH],
  uint8_t r_out[HEIGHT][WIDTH],
  uint8_t g_out[HEIGHT][WIDTH],
  uint8_t b_out[HEIGHT][WIDTH] )
{
  int row;
  int col;

  for( row=0; row<HEIGHT; row=row+1 ) {
    for( col=0; col<WIDTH; col=col+1 ) {
      int is_even_row;
      int is_even_col;
      int r;
      int g;
      int b;

      is_even_row = ( row%2==0 );
      is_even_col = ( col%2==0 );

      if( is_even_row&&is_even_col ) {
        /* R画素の位置 */
        r = get_pixel( bayer, row, col );
        g = ( get_pixel( bayer, row-1, col ) + get_pixel( bayer, row+1, col )
            + get_pixel( bayer, row, col-1 ) + get_pixel( bayer, row, col+1 ) ) / 4;
        b = ( get_pixel( bayer, row-1, col-1 ) + get_pixel( bayer, row-1, col+1 )
            + get_pixel( bayer, row+1, col-1 ) + get_pixel( bayer, row+1, col+1 ) ) / 4;
      } else if( is_even_row&&!is_even_col ) {
        /* G画素の位置(R行) */
        r = ( get_pixel( bayer, row, col-1 ) + get_pixel( bayer, row, col+1 ) ) / 2;
        g = get_pixel( bayer, row, col );
        b = ( get_pixel( bayer, row-1, col ) + get_pixel( bayer, row+1, col ) ) / 2;
      } else if( !is_even_row&&is_even_col ) {
        /* G画素の位置(B行) */
        r = ( get_pixel( bayer, row-1, col ) + get_pixel( bayer, row+1, col ) ) / 2;
        g = get_pixel( bayer, row, col );
        b = ( get_pixel( bayer, row, col-1 ) + get_pixel( bayer, row, col+1 ) ) / 2;
      } else {
        /* B画素の位置 */
        r = ( get_pixel( bayer, row-1, col-1 ) + get_pixel( bayer, row-1, col+1 )
            + get_pixel( bayer, row+1, col-1 ) + get_pixel( bayer, row+1, col+1 ) ) / 4;
        g = ( get_pixel( bayer, row-1, col ) + get_pixel( bayer, row+1, col )
            + get_pixel( bayer, row, col-1 ) + get_pixel( bayer, row, col+1 ) ) / 4;
        b = get_pixel( bayer, row, col );
      }

      r_out[row][col] = clamp_u8( r );
      g_out[row][col] = clamp_u8( g );
      b_out[row][col] = clamp_u8( b );
    }
  }
}
module bayer2x2_to_rgb #(
  parameter DATA_WIDTH = 8
) (
  input                       clk
 ,input                       rst_n
 ,input                       valid_in
 ,input      [DATA_WIDTH-1:0] bayer_00  // R
 ,input      [DATA_WIDTH-1:0] bayer_01  // G
 ,input      [DATA_WIDTH-1:0] bayer_10  // G
 ,input      [DATA_WIDTH-1:0] bayer_11  // B
 ,output reg                  valid_out
 ,output reg [DATA_WIDTH-1:0] r_out
 ,output reg [DATA_WIDTH-1:0] g_out
 ,output reg [DATA_WIDTH-1:0] b_out
);

  // 桁上がり保持のため1bit拡張して加算
  wire [DATA_WIDTH:0] g_sum;

  assign g_sum = bayer_01 + bayer_10;

  always @( posedge clk or negedge rst_n ) begin
    if( !rst_n ) begin
      valid_out <= 1'b0;
      r_out     <= {DATA_WIDTH{1'b0}};
      g_out     <= {DATA_WIDTH{1'b0}};
      b_out     <= {DATA_WIDTH{1'b0}};
    end else begin
      if( valid_in ) begin
        valid_out <= 1'b1;
        r_out     <= bayer_00;
        g_out     <= g_sum[DATA_WIDTH:1];
        b_out     <= bayer_11;
      end else begin
        valid_out <= 1'b0;
      end
    end
  end

endmodule
#include <stdint.h>

#define WIDTH  1920
#define HEIGHT 1080

/* WIDTHは偶数前提 */
/* BT.601フルレンジ係数の256倍スケール整数近似 */
/*   Y = ( 77R + 150G +  29B ) >> 8       */
/*   U = ( -43R - 85G + 128B ) >> 8 + 128 */
/*   V = ( 128R - 107G - 21B ) >> 8 + 128 */

static uint8_t clamp_u8( int val )
{
  if( val<0 ) {
    return 0;
  } else if( val>255 ) {
    return 255;
  } else {
    return (uint8_t)val;
  }
}

void rgb_to_yuv422(
  const uint8_t r_in[HEIGHT][WIDTH],
  const uint8_t g_in[HEIGHT][WIDTH],
  const uint8_t b_in[HEIGHT][WIDTH],
  uint8_t y_out[HEIGHT][WIDTH],
  uint8_t u_out[HEIGHT][WIDTH/2],
  uint8_t v_out[HEIGHT][WIDTH/2] )
{
  int row;
  int col;

  /* Y: 全画素で計算(+128は丸め) */
  for( row=0; row<HEIGHT; row=row+1 ) {
    for( col=0; col<WIDTH; col=col+1 ) {
      int y;

      y = ( 77 * r_in[row][col] + 150 * g_in[row][col] + 29 * b_in[row][col] + 128 ) >> 8;
      y_out[row][col] = clamp_u8( y );
    }
  }

  /* U/V: 水平2画素のRGB平均から全ラインで計算(4:2:2) */
  for( row=0; row<HEIGHT; row=row+1 ) {
    for( col=0; col<WIDTH; col=col+2 ) {
      int r_avg;
      int g_avg;
      int b_avg;
      int u;
      int v;

      r_avg = ( r_in[row][col] + r_in[row][col+1] + 1 ) / 2;
      g_avg = ( g_in[row][col] + g_in[row][col+1] + 1 ) / 2;
      b_avg = ( b_in[row][col] + b_in[row][col+1] + 1 ) / 2;

      /* 32896 = 32768(オフセット128<<8) + 128(丸め) */
      u = ( 32896 - 43 * r_avg - 85 * g_avg + 128 * b_avg ) >> 8;
      v = ( 32896 + 128 * r_avg - 107 * g_avg - 21 * b_avg ) >> 8;

      u_out[row][col/2] = clamp_u8( u );
      v_out[row][col/2] = clamp_u8( v );
    }
  }
}
module rgb_to_yuv422 #(
  parameter DATA_WIDTH = 8  // 係数と中間ビット幅は8bit前提
) (
  input                       clk
 ,input                       rst_n
 ,input                       valid_in
 ,input      [DATA_WIDTH-1:0] r_in
 ,input      [DATA_WIDTH-1:0] g_in
 ,input      [DATA_WIDTH-1:0] b_in
 ,output reg                  valid_y
 ,output reg [DATA_WIDTH-1:0] y_out
 ,output reg                  valid_uv
 ,output reg [DATA_WIDTH-1:0] u_out
 ,output reg [DATA_WIDTH-1:0] v_out
);

  reg                  phase;   // 0:水平ペアの1画素目, 1:2画素目
  reg [DATA_WIDTH-1:0] r_hold;
  reg [DATA_WIDTH-1:0] g_hold;
  reg [DATA_WIDTH-1:0] b_hold;

  wire [15:0]           y_pre;
  wire [DATA_WIDTH:0]   r_sum;
  wire [DATA_WIDTH:0]   g_sum;
  wire [DATA_WIDTH:0]   b_sum;
  wire [DATA_WIDTH-1:0] r_avg;
  wire [DATA_WIDTH-1:0] g_avg;
  wire [DATA_WIDTH-1:0] b_avg;
  wire [16:0]           u_pre;
  wire [16:0]           v_pre;

  // Y = ( 77R + 150G + 29B + 128(丸め) ) >> 8
  assign y_pre = 16'd77 * r_in + 16'd150 * g_in + 16'd29 * b_in + 16'd128;

  // 水平2画素の平均(+1は丸め、9bitで桁上がり保持)
  assign r_sum = r_hold + r_in + 1'b1;
  assign g_sum = g_hold + g_in + 1'b1;
  assign b_sum = b_hold + b_in + 1'b1;
  assign r_avg = r_sum[DATA_WIDTH:1];
  assign g_avg = g_sum[DATA_WIDTH:1];
  assign b_avg = b_sum[DATA_WIDTH:1];

  // 32896 = 32768(オフセット128<<8) + 128(丸め)
  // 定数を先に置くことで演算途中も非負となり符号なし演算で完結
  assign u_pre = 17'd32896 - 17'd43 * r_avg - 17'd85 * g_avg + 17'd128 * b_avg;
  assign v_pre = 17'd32896 + 17'd128 * r_avg - 17'd107 * g_avg - 17'd21 * b_avg;

  always @( posedge clk or negedge rst_n ) begin
    if( !rst_n ) begin
      phase    <= 1'b0;
      r_hold   <= {DATA_WIDTH{1'b0}};
      g_hold   <= {DATA_WIDTH{1'b0}};
      b_hold   <= {DATA_WIDTH{1'b0}};
      valid_y  <= 1'b0;
      y_out    <= {DATA_WIDTH{1'b0}};
      valid_uv <= 1'b0;
      u_out    <= {DATA_WIDTH{1'b0}};
      v_out    <= {DATA_WIDTH{1'b0}};
    end else begin
      // Y: 有効サイクルごとに1画素出力
      if( valid_in ) begin
        valid_y <= 1'b1;
        y_out   <= y_pre[15:8];
      end else begin
        valid_y <= 1'b0;
      end

      // U/V: 水平2画素に1回出力(4:2:2)
      if( valid_in ) begin
        if( phase==1'b0 ) begin
          r_hold   <= r_in;
          g_hold   <= g_in;
          b_hold   <= b_in;
          phase    <= 1'b1;
          valid_uv <= 1'b0;
        end else begin
          // u_pre/v_preは最大65536(17bit)となり得るため飽和処理
          if( u_pre[16] ) begin
            u_out <= {DATA_WIDTH{1'b1}};
          end else begin
            u_out <= u_pre[15:8];
          end
          if( v_pre[16] ) begin
            v_out <= {DATA_WIDTH{1'b1}};
          end else begin
            v_out <= v_pre[15:8];
          end
          phase    <= 1'b0;
          valid_uv <= 1'b1;
        end
      end else begin
        valid_uv <= 1'b0;
      end
    end
  end

endmodule
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?