学堂 学堂 学堂公众号手机端

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

lewis 1年前 (2024-03-28) 阅读数 7 #技术


本篇需要带你复习一下三角函数知识。不用太多,只要你知道 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/jpeg​​​,​​image/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 轴,从上到下是 yy 轴,左上角坐标是 (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 轴,但是 yy

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


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

上面的公式你完全可以改造,y y 坐标加上 size 的原因是希望图像不要太靠上方了,应该尽量位于中心,当然你可以不加这个值,再尝试输出图像看看。sin(t)sin(t)

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 图片。


版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门