在c中使用libpng编写正弦波

Posted

技术标签:

【中文标题】在c中使用libpng编写正弦波【英文标题】:Writing sine wave using libpng in c 【发布时间】:2020-02-24 14:31:06 【问题描述】:

使用 libpng。我写了一个代码(大部分是从How to change rgb values from a png image with libpng using c?复制粘贴的)。我的尝试是用波形写一个 png,但在我的正弦波中有些地方很不对:

生成此 png 的代码:

#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include "png.h"
#include <stdlib.h>
//#define _USING_MATH_DEFINES

#define ERROR 1


int width, height;

png_byte color_type;
png_byte bit_depth;
png_bytep *row_pointers;

void read_png_file(char *filename) 
  FILE *fp = fopen(filename, "rb");
  if(!fp) abort();
  png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png) abort();
  png_infop info = png_create_info_struct(png);
  if(!info) abort();
  if(setjmp(png_jmpbuf(png))) abort();
  png_init_io(png, fp);
  png_read_info(png, info);
  width      = png_get_image_width(png, info);
  height     = png_get_image_height(png, info);
  color_type = png_get_color_type(png, info);
  bit_depth  = png_get_bit_depth(png, info);
  printf("width: %d height: %d\n", width, height);

  if(bit_depth == 16)
    png_set_strip_16(png);

  if(color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_palette_to_rgb(png);

  if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    png_set_expand_gray_1_2_4_to_8(png);

  if(png_get_valid(png, info, PNG_INFO_tRNS))
    png_set_tRNS_to_alpha(png);

  if(color_type == PNG_COLOR_TYPE_RGB ||
     color_type == PNG_COLOR_TYPE_GRAY ||
     color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_filler(png, 0xFF, PNG_FILLER_AFTER);

  if(color_type == PNG_COLOR_TYPE_GRAY ||
     color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb(png);

  png_read_update_info(png, info);

  row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
  for(int y = 0; y < height; y++) 
    row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
    //printf("%d\n", row_pointers[y]);
  

  png_read_image(png, row_pointers);

  fclose(fp);


void write_png_file(char *filename) 
  int y;

  FILE *fp = fopen(filename, "wb");
  if(!fp) abort();

  png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png) abort();

  png_infop info = png_create_info_struct(png);
  if (!info) abort();

  if (setjmp(png_jmpbuf(png))) abort();

  png_init_io(png, fp);

  png_set_IHDR(
    png,
    info,
    width, height,
    8,
    PNG_COLOR_TYPE_RGBA,
    PNG_INTERLACE_NONE,
    PNG_COMPRESSION_TYPE_DEFAULT,
    PNG_FILTER_TYPE_DEFAULT
  );

  png_set_expand(png);
  png_write_info(png, info);
  png_write_image(png, row_pointers);
  png_write_end(png, NULL);

  for(int y = 0; y < height; y++) 
    free(row_pointers[y]);
  
  free(row_pointers);

  fclose(fp);


void process_png_file() 


    const int midY = ceil(height/2);
    printf("midY: %d\n", midY);
    int countY = -midY+height;
    printf("countY: %d\n", countY);
    png_byte color[] = 255,255,255;
    png_byte color_white[] = 0,0,0;
  for(int y = 0; y < height; y++) 
    png_bytep row = row_pointers[y];
    //printf("debug proc\n");

    for(int x = 0; x < width; x++) 
      png_bytep px = &(row[x * 4]);
        for(int i = 0; i < 3; ++i)
            if (y == ceil((midY-sin(x*300))))
                //printf("y: %d ceil: %d\n",y, ceil(sin(x)));
                px[i] = color[i];
            
            else 
                px[i] = color_white[i];
            

        
    
  


int main(int argc, char *argv[]) 
  if(argc != 3) abort();

  read_png_file(argv[1]);
  process_png_file();

  write_png_file(argv[2]);

  return 0;

在函数过程中,这可能是问题开始的地方:

for(int x = 0; x < width; x++) 
      png_bytep px = &(row[x * 4]);
        for(int i = 0; i < 3; ++i)
            if (y == ceil((midY-sin(x*300)))) //this part
                //printf("y: %d ceil: %d\n",y, ceil(sin(x)));
                px[i] = color[i];
            
            else 
                px[i] = color_white[i];
            

        
    

我希望它有更大的幅度。

虽然我希望代码更短,但它似乎需要像 https://github.com/mikolalysenko/lena/blob/master/lena.png 这样的虚拟 png,这就是 png 的大小看起来相同的原因。你可以删除 read_png_file() 因为我们只是在处理写作的东西(我不知道怎么做这就是为什么它是复制意大利面)。

【问题讨论】:

你需要决定像素和你正在绘制的数字之间的映射。现在,您正在获取sin() 的输出并将其视为像素数,因此 1 像素 == 1 单位。然后在水平轴上将x 乘以 300,这似乎意味着 1 个像素 == 300 个单位 == 300 弧度。如果你想要一个(比如说)50 像素高的正弦波,并且正弦波的一个周期需要更多 50 像素,你想使用像 50 * sin( x / 50 * PI) 这样的东西,当然PI 是 3.14159。 @Steve 那种工作i.imgur.com/7LDbWUQ.png... 但我会先解决差距问题。我有点知道为什么会这样。 【参考方案1】:

sin 函数接受一个以弧度表示的参数。一个完整的波只有 6.28 弧度(pi 乘以 2)。由于x 是从左侧算起的像素数,因此您为每个像素跳过了 300 弧度,这意味着您实际上每个像素跳过了 47.75 个完整的波,这看起来与向后每像素 0.25 个波相同。因此,图像中的波浪只有 4 个像素宽(每个波浪)。

我建议尝试每像素 0.1 弧度左右。这将使波浪大约 62.8 像素宽,因此它们实际上大到可以看到。将sin(x*300) 更改为sin(x*0.1)


正弦波中的 Y 值仅介于 -1 和 1 之间。由于您使用 Y 值来确定要绘制的像素,因此波只有 2 个像素高。我建议你将它乘以 50 左右,使你的波浪高 100 像素,所以它们实际上大到可以看到。将sin(whatever) 更改为sin(whatever)*50

【讨论】:

它也有一些相当的差距,但我会弄清楚的。 imgur.com/4zXOXMA 别忘了玩弄这些数字(0.1 和 50),直到您喜欢正弦波的大小。

以上是关于在c中使用libpng编写正弦波的主要内容,如果未能解决你的问题,请参考以下文章

在给定时间内将频率从 f1 缓慢上升到 f2 的正弦波

是否有可能在 AVX/SSE 中获得多个正弦波?

在mac上生成音调/正弦波的简单方法? (红宝石会很好)

使用rsound播放正弦波信号

C语言波形实现三角波和正弦波

C语言波形实现三角波和正弦波