Go語言輸出正弦函數(Sin)影象

2020-07-16 10:05:19
在Go語言中,正弦函數由 math 包提供,函數入口為 math.Sin,正弦函數的引數為 float64,返回值也是 float64。在使用正弦函數時,根據實際精度可以進行轉換。

Go語言的標準庫支援對圖片畫素進行存取,並且支援輸出各種圖片格式,如 JPEG、PNG、GIF 等。

首先給出本節完整的程式碼:
package main

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

func main() {

    // 圖片大小
    const size = 300
    // 根據給定大小建立灰度圖
    pic := image.NewGray(image.Rect(0, 0, size, size))

    // 遍歷每個畫素
    for x := 0; x < size; x++ {
        for y := 0; y < size; y++ {
            // 填充為白色
            pic.SetGray(x, y, color.Gray{255})
        }
    }

    // 從0到最大畫素生成x坐標
    for x := 0; x < size; x++ {

        // 讓sin的值的範圍在0~2Pi之間
        s := float64(x) * 2 * math.Pi / size

        // sin的幅度為一半的畫素。向下偏移一半畫素並翻轉
        y := size/2 - math.Sin(s)*size/2

        // 用黑色繪製sin軌跡
        pic.SetGray(x, int(y), color.Gray{0})
    }

    // 建立檔案
    file, err := os.Create("sin.png")

    if err != nil {
        log.Fatal(err)
    }
    // 使用png格式將資料寫入檔案
    png.Encode(file, pic) //將image資訊寫入檔案中

    // 關閉檔案
    file.Close()
}

設定圖片背景色

以下是設定圖片背景的程式碼:
// 圖片大小
const size = 300

// 根據給定大小建立灰度圖
pic := image.NewGray(image.Rect(0, 0, size, size))

// 遍歷每個畫素
for x := 0; x < size; x++ {
    for y := 0; y < size; y++ {
        // 填充為白色
        pic.SetGray(x, y, color.Gray{255})
    }
}
程式碼說明如下:
  • 第 2 行,宣告一個 size 常數,值為 300。
  • 第 5 行,使用 image 包的 NewGray() 函數建立一個圖片物件,使用區域由 image.Rect 結構提供,image.Rect 描述一個方形的兩個定位點 (x1,y1) 和 (x2,y2),image.Rect(0,0,size,size) 表示使用完整灰度影象素,尺寸為寬 300,長 300。
  • 第 8 行和第 9 行,遍歷灰度圖的所有畫素。
  • 第 11 行,將每一個畫素的灰度設為 255,也就是白色。

灰度圖是一種常見的圖片格式,一般情況下顏色由 8 位組成,灰度範圍為 0~255,0 表示黑色,255 表示白色。

初始化好的灰度圖預設的灰度值都是 0,對的是黑色,由於顯示效果的效果不是很好,所以這裡將所有畫素設定為 255,也就是白色。

繪製正弦函數軌跡

正弦函數是一個週期函數,定義域是實數集,取值範圍是 [-1, 1]。用程式設計的通俗易懂的話來說就是:math.Sin 函數的引數支援任意浮點數範圍,函數返回值的範圍總是在 -1~1 之間(包含 1、-1)。

要將正弦函數放在圖片上需要考慮以下一些因素:
  • math.Sin 的返回值在 -1~1 之間,需要考慮將正弦的輸出幅度變大,可以將 math.Sin 的返回值乘以一個常數進行放大。
  • 圖片的坐標系原點在左上角,而 math.Sin 基於笛卡爾坐標系原點在左下角,需要對影象進行上下翻轉和平移。

將這些處理邏輯匯總為程式碼如下:
// 從0到最大畫素生成x坐標
for x := 0; x < size; x++ {

    // 讓sin的值的範圍在0~2Pi之間
    s := float64(x) * 2 * math.Pi / size

    // sin的幅度為一半的畫素。向下偏移一半畫素並翻轉
    y := size/2 - math.Sin(s)*size/2

    // 用黑色繪製sin軌跡
    pic.SetGray(x, int(y), color.Gray{0})
}
程式碼說明如下:
1) 第 2 行,生成 0 到 size(300)的 x 坐標軸。

2) 第 5 行,計算 math.Sin 的定義域,這段程式碼等效為:
rate := x / size
s := rate * 2 * math.Pi
x 的範圍是 0 到 size,因此除以 size 後,rate 的範圍是 0~1 之間,再乘以 2π 後,s 的範圍剛好是 0~2π 之間。

float64(x) 表示將整型的 x 變數轉換為 float64 型別,之後運算的所有表示式將以 float64 型別進行。

3) 第 8 行中,math.Sin(s)*size/2 表示將正弦函數的返回值幅度從 1 擴大到二分之一的 size。負號表示將正弦函數圖形以圖形中心上下翻轉。疊加 size/2 表示將圖形在 y 軸上向下偏移二分之一的 size(圖片坐標系的 y 向下)。

4) 第 11 行將計算好的 x 軸和 y 軸資料,以灰度為 0(黑色)使用 SetGray() 方法填充到畫素中。

寫入圖片的正弦函數影象如下圖所示: