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

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


这里写图片描述
图1 y=sin(x) y = s i n ( x ) 图像

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


这里写图片描述
图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 x 轴,从上到下是 y 轴,左上角坐标是 (0,0) ( 0 , 0 )


这里写图片描述
图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 x 轴就是图3 里的 x 轴,但是 y 轴方向和我们在数学课上学到的是反的,其实这无关紧要。

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

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

上面的公式你完全可以改造, y 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 图片。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值