欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

007-绘制三角函数图像(一)

程序员文章站 2022-03-11 10:17:28
...

本篇需要带你复习一下三角函数知识。不用太多,只要你知道 y=sin(x) 是什么样子就行了。什么?忘记长啥样了?看下面。


007-绘制三角函数图像(一)
图1 y=sin(x) 图像

我们的目标是,使用 go 语言生成一幅 y=sin(x) 的曲线图像出来, jpeg 或者 png 随便你。下面是使用 go 生成图像的一个例子。


007-绘制三角函数图像(一)
图2 使用 go 生成的 png 图像

虽然有点丑,但是美化的目标就交给你了。

1. 基础知识

1.1 相关的包介绍

主要使用的包有这三类

  • image,在内存里创建图像会用到这个包的相关函数。
  • image/color,和颜色相关的函数都在这里。
  • image/png,将内存里的图像编码png文件。

类似 png 的包还有 image/jpegimage/gif 这些包,它们的功能都是将内存里的像素信息编码成具体某种格式的图片。

1.2 相关的概念

  • 彩色图像

彩色图像是一个矩形,由一行一行的像素点组成,每个像素点有自己的颜色。这些颜色的类型可以是 RGBA 类型,也可以是 CMYK 类型。本文只介绍 RGBA 类型。

RGBA 是 Red-Green-Blue-Alpha 的首字母缩写,使用 R, G, B 就可以控制像素的颜色,使用 A 可以控制像素的透明度。

绘制图像的基本原理就是给矩形中每个像素设置一个颜色。

  • in-memory image

在内存中的图像,是指还没有被编码成具体格式的图像数据。只要有了 in-memory image,我们就可以将其编码成任意格式的图像。我们可以把 in-memory image 看成是图 3 里的样子,从左到右是 x 轴,从上到下是 y 轴,左上角坐标是 (0,0)


007-绘制三角函数图像(一)
图3 in-memory image

在 go 语言中,in-memory image 有很多种,但是他们都需要实现 image.Image 接口。接口的概念我们还没有正式学过,这里暂且认为它是某个抽象类,定义了以下几个方法:

type Image interface {
        ColorModel() color.Model
        Bounds() Rectangle
        At(x, y int) color.Color
}

1.3 编码成具体格式的图像

只要有了 in-memory image,我们就可以使用某种编码器,比如 jpeg 来将其编码成 jpeg 的 2 进制图像数据,然后保存到本地。

jpeg.Encode(file, in-memory image)

2. 程序

2.1 原理

绘制部分的主要原理就是给 in-memory image 里的像素填颜色。就好比图像 3 里那样,要想绘制图三角函数图像,就需要在图 3 里找到正确的像素小方格,填充好颜色。

难点在于,要给哪些像素点填充颜色?这里,我们不妨就假设 x 轴就是图3 里的 x 轴,但是 y 轴方向和我们在数学课上学到的是反的,其实这无关紧要。

假设图像是个正方形,其边长是 2×size 个像素,则需要绘制的坐标点应该像下面这个参数公式(使用参数 t 来控制 xy

x=2×size×t2πy=size+100×sin(t)t[0,2π]

上面的公式你完全可以改造,y 坐标加上 size 的原因是希望图像不要太靠上方了,应该尽量位于中心,当然你可以不加这个值,再尝试输出图像看看。sin(t) 乘以 100 是为了让三解函数这幅值变化更大一点,这样显的不是那么扁。这些参数你都可以任意更改,这也算是一个作业。

2.2 实现

创建的文件名字叫 sin1.go. 文件路径是 gopl/tutorial/image/rgba/sin1.go

// sin1.go
package main

import (
    "fmt"
    "image"
    "image/color"
    "image/png"
    "math"
    "os"
)

const (
    size = 128 // 常量
)

func main() {
    rec := image.Rect(0, 0, 2*size, 2*size) // 创建矩形画布
    image := image.NewRGBA(rec) // 返回一个 in-memory image
    c := color.RGBA{0xff, 0, 0, 0xff} // 定义一个红色值
    // 下面两个 for 循环是把 in-memory 中所有的像素初始化为灰色 #eeeeee
    for x := 0; x < 2*size; x++ {
        for y := 0; y < 2*size; y++ {
            image.Set(x, y, color.RGBA{0xee, 0xee, 0xee, 0xff})
        }
    }
    // 绘制 sin 函数曲线
    for t := 0.0; t < 2*math.Pi; t += 0.001 {
        x := int(2.0*size*t/(2.0*math.Pi) + 0.5) // 加 0.5 是为了4舍5入
        y := int(size + 100*math.Sin(t) + 0.5)
        image.Set(x, 2*size-y, c) // 给对应的像素位置设置颜色值
    }

    // 将 in-memory image 编码成 png 格式数据,并写入标准输出。
    err := png.Encode(os.Stdout, image) 
    if err != nil {
        fmt.Fprintf(os.Stderr, "%v\n", err)
    }
}

2.3 运行

$ go run sin1.go > a.png

这样就生成了一幅三角函数图像啦。

2.4 分析

  • 常量

在 go 里,常量使用 const 关键字声明,且只能是数字、字符串和布尔值。在上面的程序里,我们声明了一个 size 常量,它在需要的时候,可以转换成 int 类型,也可以转换成 float64 类型。具体转换成什么类型,就看它怎么使用了。

关于常量,后面还会详细介绍。

  • color.RGBA

这种类型有点像我们在 c/c++ 里学习的结构体,在 go 里它被称之为复合类型。在我们程序里,我们使用 color.RGBA{...} 初始化一个颜色值,这是复合类型初始化的一种方法。关于复合类型,后续还会介绍。

3. 总结

  • 了解 go 语言更多的语法结构
  • 了解 go 语言强大的包支持,知道 go 语言可以非常方便的做很多事情

练习:

1. 通过命令行参数来控制三角函数曲线的『频率,幅值和相位』。
2. 更改曲线的颜色。
3. 编码成 jpeg 图片。
相关标签: go image