吃到飽變吃不飽?電動機車商用資費為何如此難算?

近日 Gogoro 電池月租吃到飽方案引發爭議,對於如何定義商用,以及如何舉證開罰,各界都有不同看法,但 Gogoro 先是強調不再寬待,昨夜又臨時發表聲明政策轉彎,然而品牌形象已經產生傷害。究竟 Gogoro 為何如此堅持,而電動機車的資費又應該怎麼設計會更合理呢?

近日由於網友貼出了一張 Gogoro 寄送的「違規使用通知信」,而讓吃到飽方案成為爭論焦點。我們快速整理一下目前的重點。

  1. Gogoro 月租 899 吃到飽方案,禁止商業使用。
  2. 連續兩個月里程超過 1,600 公里,將被視為商業使用而開罰。
  3. 用戶收到通知後,可以回寄照片證明是用於出遊或長程通勤,即可免罰。
  4. 有路人開始檢舉外送員騎 gogoro 送餐。
  5. Gogoro 發公開信,5/10 起若被檢舉,無論里程長短,將直接變更為商用方案。
  6. Gogoro 修改標準,需連續兩個月里程超過 1,600 公里且被檢舉商業使用才開罰。

且不談這次資費爭議,我們此時可以想的一件事情是,如果燃油車終將被淘汰,電動車需要怎樣的能源費用標準才合理?

假設以每月 1,600 公里為使用里程來計算,目前各種能源方案以 Gogoro 商業型最貴,七期燃油車最便宜,充電式機車在光陽調降月租費用之後,如果採用兩顆電池方案,再加上全部在家充電,費用也相當便宜。

每月騎 1,600 公里,機車能源費用比較。(圖片來源:科技新報製)

不過 IONEX 方案並未說明是否可作為商業使用,而且月租費 398 方案限定綁約兩年,期滿後回到原價 598 元,這個方案還提供 2,000 公里里程,算是相當優惠,如果能夠在家充電的話,是一個不錯的選項。(充電時間約 4 小時)

而燃油車在油價狂降的此刻,商用優勢更為明顯,即使九五汽油價格回升到 30 元,每月費用仍然不到一千元,當然前提是要騎乘七期燃油車,才有每公升 50 公里的低油耗表現。

Gogoro 商業方案的天價,讓人望之卻步,為什麼會訂出這麼高的金額呢?雖然 Gogoro 官方並未明說,但顯然換電站建置與電池成本,如果在頻繁換電情況下,確實讓 Gogoro 電網不堪負荷,而原本換電的優勢也因為電池來不及充飽而打折,因此官方才祭出強硬手腕。

Gogoro 第二次政策轉彎,重新定義吃到飽違約標準。(Source:)

但 Gogoro 滿街跑對於官方來說又是最佳宣傳,所以之前才會容許模糊地帶存在,但是當其他車主開始檢舉之後,官方也不得不有所回應。經過兩次轉彎,最新的定調是,連續兩個月里程超過 1,600 公里且經檢舉才會視為商業使用。換句話說,如果偶爾兼差外送,並不會被追討違約金。

按照 Gogoro 官方說法,為了 99% 的用戶著想,他們願意放寬認定標準,但也看得出來,換電站與電池流通量不足,才是這次爭議真正的核心。否則何必為了 0.3% 的極少數用戶,而鬧出滿城風雨。

而充電式機車像是 e-moving 推出的商用版 ie PICKUP,則看準 Gogoro 在這個領域的不足,期望能夠搶佔商用電動機車市場,電池租賃方案分別為 399 元/月基礎型(家充不限里程)、599 元/月輕量型提供 100 分鐘超級充電時數、799 元/月進階型提供 400 分鐘,合約皆為 2 年一簽,車輛定價則為 83,800 元。

光陽 IONEX 的電池租用方案費用較低,但需要用戶自行在家充電,或是找快充站付費充電。(圖片來源:)

那麼充電式機車會是商用機車的新未來嗎?這仍要取決於未來充電式機車的性能是否有充足進步,以 IONEX 為例,定價 66,800 元新台幣,極速在 60 km/h 以下,在理想狀態下的滿電續航里程為 60 km,而快充到滿需要一個小時(額外付費),要作為商業使用,恐怕還有所不足。更何況當前資費方案,其實是因為用戶量極少,才推出的短期優惠,未來如果用戶增加,會否漲價,或是加入禁止商用條款也未可知。

電動車要商用化的另一項挑戰,來自於維修保養體系,對於商業用戶來說,時間就是金錢,而據點少、難預約的電動機車服務站,在這一點就輸給發展許久的油車一大截了。

以目前兩種電動機車的型態來看,換電系統對於使用者來說比較符合商用需求,但營運商成本較高;充電系統雖然有價格優勢,卻輸在車輛性能與時間彈性上。在可見的將來,全面禁用燃油車幾乎已是定局,若要讓商用機車能夠全面電動化,勢必需要更多的基礎建設(充電站、換電站、保修據點)才能拉低成本與里程焦慮,在那之前,恐怕難有比現在更好的作法。

最終我們建議,Gogoro 不該繼續在模糊地帶打轉,而是仔細估算商用方案的定價,相信如果能夠將方案價格調降到 1,500 元以下,或是與外送平台、快遞業者合作推優惠方案,讓商用族群可以正正當當的「吃到飽」,而不是每個月精算里程才是正途。試想,如果滿街的外送員都騎電動車,不正是電動車的一大勝利嗎?

(合作媒體:。首圖來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

Python 圖像處理 OpenCV (12): Roberts 算子、 Prewitt 算子、 Sobel 算子和 Laplacian 算子邊緣檢測技術

前文傳送門:

「Python 圖像處理 OpenCV (1):入門」

「Python 圖像處理 OpenCV (2):像素處理與 Numpy 操作以及 Matplotlib 显示圖像」

「Python 圖像處理 OpenCV (3):圖像屬性、圖像感興趣 ROI 區域及通道處理」

「Python 圖像處理 OpenCV (4):圖像算數運算以及修改顏色空間」

「Python 圖像處理 OpenCV (5):圖像的幾何變換」

「Python 圖像處理 OpenCV (6):圖像的閾值處理」

「Python 圖像處理 OpenCV (7):圖像平滑(濾波)處理」

「Python 圖像處理 OpenCV (8):圖像腐蝕與圖像膨脹」

「Python 圖像處理 OpenCV (9):圖像處理形態學開運算、閉運算以及梯度運算」

「Python 圖像處理 OpenCV (10):圖像處理形態學之頂帽運算與黑帽運算」

「Python 圖像處理 OpenCV (11):Canny 算子邊緣檢測技術」

引言

前文介紹了 Canny 算子邊緣檢測,本篇繼續介紹 Roberts 算子、 Prewitt 算子、 Sobel 算子和 Laplacian 算子等常用邊緣檢測技術。

Roberts 算子

Roberts 算子,又稱羅伯茨算子,是一種最簡單的算子,是一種利用局部差分算子尋找邊緣的算子。他採用對角線方向相鄰兩象素之差近似梯度幅值檢測邊緣。檢測垂直邊緣的效果好於斜向邊緣,定位精度高,對噪聲敏感,無法抑制噪聲的影響。

1963年, Roberts 提出了這種尋找邊緣的算子。 Roberts 邊緣算子是一個 2×2 的模版,採用的是對角方向相鄰的兩個像素之差。

Roberts 算子的模板分為水平方向和垂直方向,如下所示,從其模板可以看出, Roberts 算子能較好的增強正負 45 度的圖像邊緣。

\[dx = \left[ \begin{matrix} -1 & 0\\ 0 & 1 \\ \end{matrix} \right] \]

\[dy = \left[ \begin{matrix} 0 & -1\\ 1 & 0 \\ \end{matrix} \right] \]

Roberts 算子在水平方向和垂直方向的計算公式如下:

\[d_x(i, j) = f(i + 1, j + 1) – f(i, j) \]

\[d_y(i, j) = f(i, j + 1) – f(i + 1, j) \]

Roberts 算子像素的最終計算公式如下:

\[S = \sqrt{d_x(i, j)^2 + d_y(i, j)^2} \]

今天的公式都是小學生水平,千萬別再說看不懂了。

實現 Roberts 算子,我們主要通過 OpenCV 中的 filter2D() 這個函數,這個函數的主要功能是通過卷積核實現對圖像的卷積運算:

def filter2D(src, ddepth, kernel, dst=None, anchor=None, delta=None, borderType=None)
  • src: 輸入圖像
  • ddepth: 目標圖像所需的深度
  • kernel: 卷積核

接下來開始寫代碼,首先是圖像的讀取,並把這個圖像轉化成灰度圖像,這個沒啥好說的:

# 讀取圖像
img = cv.imread('maliao.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化處理圖像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

然後是使用 Numpy 構建卷積核,並對灰度圖像在 x 和 y 的方向上做一次卷積運算:

# Roberts 算子
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)

x = cv.filter2D(grayImage, cv.CV_16S, kernelx)
y = cv.filter2D(grayImage, cv.CV_16S, kernely)

注意:在進行了 Roberts 算子處理之後,還需要調用convertScaleAbs()函數計算絕對值,並將圖像轉換為8位圖進行显示,然後才能進行圖像融合:

# 轉 uint8 ,圖像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Roberts = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

最後是通過 pyplot 將圖像显示出來:

# 显示圖形
titles = ['原始圖像', 'Roberts算子']
images = [rgb_img, Roberts]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

最終結果如下:

Prewitt 算子

Prewitt 算子是一種一階微分算子的邊緣檢測,利用像素點上下、左右鄰點的灰度差,在邊緣處達到極值檢測邊緣,去掉部分偽邊緣,對噪聲具有平滑作用。

由於 Prewitt 算子採用 3 * 3 模板對區域內的像素值進行計算,而 Robert 算子的模板為 2 * 2 ,故 Prewitt 算子的邊緣檢測結果在水平方向和垂直方向均比 Robert 算子更加明顯。Prewitt算子適合用來識別噪聲較多、灰度漸變的圖像。

Prewitt 算子的模版如下:

\[dx = \left[ \begin{matrix} 1 & 0 & -1\\ 1 & 0 & -1\\ 1 & 0 & -1\\ \end{matrix} \right] \]

\[dy = \left[ \begin{matrix} -1 & -1 & -1\\ 0 & 0 & 0\\ 1 & 1 & 1\\ \end{matrix} \right] \]

在代碼實現上, Prewitt 算子的實現過程與 Roberts 算子比較相似,我就不多介紹,直接貼代碼了:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖像
img = cv.imread('maliao.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化處理圖像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# Prewitt 算子
kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]],dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]],dtype=int)

x = cv.filter2D(grayImage, cv.CV_16S, kernelx)
y = cv.filter2D(grayImage, cv.CV_16S, kernely)

# 轉 uint8 ,圖像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Prewitt = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# 用來正常显示中文標籤
plt.rcParams['font.sans-serif'] = ['SimHei']

# 显示圖形
titles = ['原始圖像', 'Prewitt 算子']
images = [rgb_img, Prewitt]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

從結果上來看, Prewitt 算子圖像銳化提取的邊緣輪廓,其效果圖的邊緣檢測結果比 Robert 算子更加明顯。

Sobel 算子

Sobel 算子的中文名稱是索貝爾算子,是一種用於邊緣檢測的離散微分算子,它結合了高斯平滑和微分求導。

Sobel 算子在 Prewitt 算子的基礎上增加了權重的概念,認為相鄰點的距離遠近對當前像素點的影響是不同的,距離越近的像素點對應當前像素的影響越大,從而實現圖像銳化並突出邊緣輪廓。

算法模版如下:

\[dx = \left[ \begin{matrix} 1 & 0 & -1\\ 2 & 0 & -2\\ 1 & 0 & -1\\ \end{matrix} \right] \]

\[dy = \left[ \begin{matrix} -1 & -2 & -1\\ 0 & 0 & 0\\ 1 & 2 & 1\\ \end{matrix} \right] \]

Sobel 算子根據像素點上下、左右鄰點灰度加權差,在邊緣處達到極值這一現象檢測邊緣。對噪聲具有平滑作用,提供較為精確的邊緣方向信息。因為 Sobel 算子結合了高斯平滑和微分求導(分化),因此結果會具有更多的抗噪性,當對精度要求不是很高時, Sobel 算子是一種較為常用的邊緣檢測方法。

Sobel 算子近似梯度的大小的計算公式如下:

\[G = \sqrt{d_X^2 + d_y^2} \]

梯度方向的計算公式如下:

\[\theta = \tan^{-1}(\frac {d_x}{d_y}) \]

如果以上的角度 θ 等於零,即代表圖像該處擁有縱向邊緣,左方較右方暗。

在 Python 中,為我們提供了 Sobel() 函數進行運算,整體處理過程和前面的類似,代碼如下:

import cv2 as cv
import matplotlib.pyplot as plt

# 讀取圖像
img = cv.imread('maliao.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化處理圖像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# Sobel 算子
x = cv.Sobel(grayImage, cv.CV_16S, 1, 0)
y = cv.Sobel(grayImage, cv.CV_16S, 0, 1)

# 轉 uint8 ,圖像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Sobel = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# 用來正常显示中文標籤
plt.rcParams['font.sans-serif'] = ['SimHei']

# 显示圖形
titles = ['原始圖像', 'Sobel 算子']
images = [rgb_img, Sobel]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

Laplacian 算子

拉普拉斯( Laplacian )算子是 n 維歐幾里德空間中的一個二階微分算子,常用於圖像增強領域和邊緣提取。

Laplacian 算子的核心思想:判斷圖像中心像素灰度值與它周圍其他像素的灰度值,如果中心像素的灰度更高,則提升中心像素的灰度;反之降低中心像素的灰度,從而實現圖像銳化操作。

在實現過程中, Laplacian 算子通過對鄰域中心像素的四方向或八方向求梯度,再將梯度相加起來判斷中心像素灰度與鄰域內其他像素灰度的關係,最後通過梯度運算的結果對像素灰度進行調整。

Laplacian 算子分為四鄰域和八鄰域,四鄰域是對鄰域中心像素的四方向求梯度,八鄰域是對八方向求梯度。

四鄰域模板如下:

\[H = \left[ \begin{matrix} 0 & -1 & 0\\ -1 & 4 & -1\\ 0 & -1 & 0\\ \end{matrix} \right] \]

八鄰域模板如下:

\[H = \left[ \begin{matrix} -1 & -1 & -1\\ -1 & 4 & -1\\ -1 & -1 & -1\\ \end{matrix} \right] \]

通過模板可以發現,當鄰域內像素灰度相同時,模板的卷積運算結果為0;當中心像素灰度高於鄰域內其他像素的平均灰度時,模板的卷積運算結果為正數;當中心像素的灰度低於鄰域內其他像素的平均灰度時,模板的卷積為負數。對卷積運算的結果用適當的衰弱因子處理並加在原中心像素上,就可以實現圖像的銳化處理。

在 OpenCV 中, Laplacian 算子被封裝在 Laplacian() 函數中,其主要是利用Sobel算子的運算,通過加上 Sobel 算子運算出的圖像 x 方向和 y 方向上的導數,得到輸入圖像的圖像銳化結果。

import cv2 as cv
import matplotlib.pyplot as plt

# 讀取圖像
img = cv.imread('maliao.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化處理圖像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# Laplacian
dst = cv.Laplacian(grayImage, cv.CV_16S, ksize = 3)
Laplacian = cv.convertScaleAbs(dst)

# 用來正常显示中文標籤
plt.rcParams['font.sans-serif'] = ['SimHei']

# 显示圖形
titles = ['原始圖像', 'Laplacian 算子']
images = [rgb_img, Laplacian]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

最後

邊緣檢測算法主要是基於圖像強度的一階和二階導數,但導數通常對噪聲很敏感,因此需要採用濾波器來過濾噪聲,並調用圖像增強或閾值化算法進行處理,最後再進行邊緣檢測。

最後我先使用高斯濾波去噪之後,再進行邊緣檢測:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 讀取圖像
img = cv.imread('maliao.jpg')
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化處理圖像
gray_image = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# 高斯濾波
gaussian_blur = cv.GaussianBlur(gray_image, (3, 3), 0)

# Roberts 算子
kernelx = np.array([[-1, 0], [0, 1]], dtype = int)
kernely = np.array([[0, -1], [1, 0]], dtype = int)
x = cv.filter2D(gaussian_blur, cv.CV_16S, kernelx)
y = cv.filter2D(gaussian_blur, cv.CV_16S, kernely)
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Roberts = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# Prewitt 算子
kernelx = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int)
kernely = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=int)
x = cv.filter2D(gaussian_blur, cv.CV_16S, kernelx)
y = cv.filter2D(gaussian_blur, cv.CV_16S, kernely)
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Prewitt = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# Sobel 算子
x = cv.Sobel(gaussian_blur, cv.CV_16S, 1, 0)
y = cv.Sobel(gaussian_blur, cv.CV_16S, 0, 1)
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Sobel = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# 拉普拉斯算法
dst = cv.Laplacian(gaussian_blur, cv.CV_16S, ksize = 3)
Laplacian = cv.convertScaleAbs(dst)

# 展示圖像
titles = ['Source Image', 'Gaussian Image', 'Roberts Image',
          'Prewitt Image','Sobel Image', 'Laplacian Image']
images = [rgb_img, gaussian_blur, Roberts, Prewitt, Sobel, Laplacian]
for i in np.arange(6):
   plt.subplot(2, 3, i+1), plt.imshow(images[i], 'gray')
   plt.title(titles[i])
   plt.xticks([]), plt.yticks([])
plt.show()

示例代碼

如果有需要獲取源碼的同學可以在公眾號回復「OpenCV」進行獲取。

參考

https://blog.csdn.net/Eastmount/article/details/89001702

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

Shader專題:卡通着色(一)控制顏色的藝術

什麼是 Shader?

關於什麼是 Shader ,各種百科各種教程都有說過,但是今天我們就從一個另一個角度去試着理解什麼是 Shader?

我們先看下 Shade 的英文意思,如下:
v.給…遮擋(光線);把…塗暗

其中 把…塗暗 更貼近我們想要的意思。
所以:Shader 這個單詞從字面上理解,就是把什麼東西塗暗。

再強調一次:Shader 從單詞字面上理解,就是把什麼東西塗暗。
再強調一次:把什麼東西塗暗的就是 Shader,就是着色器。

Shader 把什麼塗暗了?

當然是遊戲世界的各個物體,總所周知:有光明就有黑暗,有光照物體就有明暗對比,同時也會有陰影,而 Shader 之所以叫 Shader 是因為起初的時候,Shader 就是用來給物體增加明暗對比的,有了明暗對比,物體在遊戲世界中就會更加立體,從而畫面會更加真實。

所以 Shader 的作用就是給物體添加明暗對比。

Shader 為什麼叫 Shader

當然以上純屬個人推測。現在 Shader 不止可以給物體添加明暗對比,而且還可以做很多濾鏡效果,也可以做很多性能優化(比如減少包大小、減少圖片內存等)的事情。

也許,一開始給 Shader 起名叫 Shader 的時候,Shader 功能非常有限,僅僅只是給物體添加明暗對比(也就是光照計算),後來由於硬件和軟件的發展, 很多離線渲染(電影 CG)的算法都逐步應用在實時渲染(主要是 遊戲 和3D 仿真等),Shader 能做的事情就越來越多,發展到今天,Shader 主要的功能並不只有光照計算。這樣導致,在概念理解上給很多初學者增加了很多阻礙。

教練有一次聽過一位搞圖形學的朋友說:“我們搞實時渲染的都是那些搞視頻(離線渲染)玩剩的”。

Shader 是着色器

什麼是 Shader,中文叫做着色器,也就是給物體上色的意思,也就是說寫 Shader 就是給物體上色的藝術。而這個上色不只是簡單的色彩填充,而是涵蓋了非常多的技巧(幾何計算、顏色計算、貼圖等)

所以中文的着色器,是一個非常精準的翻譯。

群內的笑笑說了一個比較不錯的說法:Shader 主要是光線數據作用在不同數據的物體上產生不同效果。

Shader 學習的順序

不管是 Shader 還是其它某個科目,都有一些最常用、最簡單的知識點。

而這些知識點很容易學以致用,也就是說,這種知識點,我們學習完了就能馬上落地。

所以,教練要做的就是,把 Shader 中的知識點按照是否常用和是否簡單這兩個維度進行排列篩選,然後把它們一個個整理成案例,這樣童鞋們的學習體驗就會大幅上升。

主題式研究第三個階段

  • 第一個階段:確定主題(關鍵字)
  • 第二個階段:搜索資料、搜索信息(搜集情報)
  • 第三個階段:構建知識體系(畫腦圖、寫大綱)

到此,Shader 這個主題,我們目前已經到了第三個階段,也就是構建知識體系的階段。

當然,這一整篇,都再講,我們要怎麼怎麼做,接下來幹嗎,並沒有學習 Shader 的任何一個知識點。

那麼今天就學習一點 Shader 知識意思一下。

顏色的控制

現有一張貼圖,如下:

用來控制顏色的 shader 代碼如下:

float4 frag (v2f i) : SV_Target
{
    // 圖片上每個像素的顏色值
    float4 color = tex2D(_MainTex, i.uv);
                
    // 返回顏色,表示將改像素的顏色值輸出到屏幕上
    return color;
}

我們只看方法中的代碼,先不要在意一些細節。

雖然,我們沒有 Shader 的語法學習經驗,但是憑我們的 C# 經驗,可以將上述代碼推測個大概來。

首先 float4 是一個類型,可以存儲 4 個 float 數值。而顏色一般都是由 r(red 紅色)、g(green,綠色)、b(blue,藍色)、a(alpha,透明度) 四個值控制。所以 float4 可以存儲一個顏色。

現在,我們把圖片中每個像素顏色重的紅色值設置為 0,圖片結果則如下所示:

代碼如下所示:

float4 frag (v2f i) : SV_Target
{
    // 圖片上每個像素的顏色值
    float4 color = tex2D(_MainTex, i.uv);
                
    color.r = 0;

    // 返回顏色,表示將改像素的顏色值輸出到屏幕上
    return color;
}

我們看到,圖片變成了藍綠色。

小結

Shader 是一門控制顏色的藝術,Shader 的核心也是如此。
在此篇,我們學習了 Shader 的兩個重要知識點:

  1. float4 結構體
  2. 顏色的 rgb 控制

這兩個知識點非常簡單,也非常基礎,但是是非常常用的兩個知識點。

這片文章的內容就這些。

知識地圖

相關下載:

轉載請註明地址:liangxiegame.com

更多內容
QFramework 地址:https://github.com/liangxiegame/QFramework
QQ 交流群:623597263
涼鞋的主頁:https://liangxiegame.com/zhuanlan
關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

澳洲野火持續燃燒 摧毀約四成台灣面積

整理:劉妙慈(環境資訊中心實習編輯)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

Nissan、BMW聯手 在美安裝更多電動車充電樁

Nissan與BMW宣布,為共同強化各自旗下的電動車產品Nissan LEAF與BMW i3的客戶服務網,將合作在全美19州、共120處安裝雙頭快速充電樁。此舉未來可望刺激美國市場的電動車銷售量,並幫助電動車車主享有更便捷、廣泛的服務。

Nissan LEAF是目前全球總銷量最好的電動車款之一,充電樁設備分布在社區、企業公司以及Nissan的經銷門市。與BMW的合作,將可加速提升充電樁設備的數量,強化用戶使用經驗同時開拓市場。

BMW的北美電子移動經理Cliff Fietzek強調,與Nissan的合作還包含遠程行車的服務。一但電動車能提供更遠程的行駛距離,使用者就更能體驗電子移動科技的便利之處。

這項合作將以Nissan的充電樁技術與BMW的DC快充技術為基礎,每座快充充電樁都有CHAdeMO與SAE Combo雙街頭,輸出功率50kW,可適用於Nissan LEAF與BMW i3兩種車款以及其他擁有快充埠的電動車。50kW的快充設備可在20-30分鐘之內將Nissan LEAF或BMW i3的電池充到80%左右,比目前最常見的Level 2 240V 充電服務的效率更好。

Nissan與BMW的電動車充電樁服務範圍包括:加州、康乃迪克州、佛羅里達、喬治亞州、伊利諾州、印第安納州、馬里蘭州、明尼蘇達州、密蘇里州、新墨西哥州、內華達州、紐約、南北卡羅萊納州、俄亥俄州、賓州、田納西州、維吉尼亞州以及威斯康辛州。只要透過BWM i3的ConnectedDrive軟體,或者Nissan EZ-Charge智慧型手機app,就能快速找到充電站位置,電費可用Nissan EZ-Charge卡片結帳。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

C表達式中的彙編指令

C 表達式中的彙編指令

asm 為 gcc 中的關鍵字,asm 表達式為在 C代碼中嵌套彙編指令,該表達式只是單純的替換出彙編代碼,並不對彙編代碼的含義進行解析。

asm 表達式有兩種形式,第二種 asm-qualifiers 包含了 goto 語句。
第一種形式為常見的用法,AssemblerTemplate 和 OutputOperands 必須存在, 其中 Clobbers 存在需要 InputOperands 也出現。

asm asm-qualifiers ( AssemblerTemplate 
                 : OutputOperands 
                 [ : InputOperands
                 [ : Clobbers ] ])

asm asm-qualifiers ( AssemblerTemplate 
                      : 
                      : InputOperands
                      : Clobbers
                      : GotoLabels)

Qualifiers 的類型

  • volatile, 避免編譯器的優化
  • inline, 內斂限定符,最小的體積
  • goto, 包含跳轉指令

參數

  • AssemblerTemplate
    – 彙編指令模板是包含彙編器指令的文字字符串,編輯器替換引用輸入,編譯器不會解析該指令的含義。
  • OutputOperands
    – 由 AssemblerTemplate 中的指令修改的C變量的逗號分隔列表,允許使用空列表。
  • InputOperands
    – 由 AssemblerTemplate 中的指令讀取的C變量的逗號分隔列表,允許使用空列表。
  • Clobbers
    – 用逗號分隔的寄存器列表或由 AssemblerTemplate 修改的值,不能出現在 OutputOperands 和 InputOperands 中被提及,允許使用空列表。
  • GotoLabels
    – 當使用asm的goto形式時,此部分包含 AssemblerTemplate 中的代碼可能跳轉到的所有C標籤的列表。

AssemblerTemplate

彙編指令由一個字符串給出,多條彙編指令結合在一起使用的時候,中間以 \r\t 隔開,如

asm("inc %0\n\tinc %0" : "=r"(res) : "0"(res));

/APP
# 11 "asm.c" 1
        inc %rax
        inc %rax
# 0 "" 2
/NO_APPs

需要轉義的字符:%, =, {, }, |

故在ATT彙編中,對寄存器進行操作的需要雙 %%, 如 inc %%rax.

OutputOperands

操作數之間用逗號分隔。 每個操作數具有以下格式:

[ [asmSymbolicName] ] constraint (cvariablename)
  • asmSymbolicName
    – 為操作數指定名稱,格式為 %[name]
    c // res = num asm("movq %[num], %[res]" : [res] "=r"(res) : [num] "m"(num));
    – 如果未指定名稱使用数字, 從 output 域開始,第一個參數為 %0, 一次類推, 這裏的 res 為 %0, num 為 %1
    c // res = num asm("movq %1, %0" : "=r"(res) : "m"(num));
  • constraint
    – 一個字符串常量,用於指定對操作數的存儲的 , 需要以 “=” 或 “+” 開頭
  • cvariablename
    – 指定一個C左值表達式來保存輸出,通常是一個變量名。 括號是語法的必需部分

第一個參數為增加可讀性使用的,現在我們有代碼如下

int64_t res;
int64_t num = 1;

asm("movq %[num], %[res]" : [res] "=r"(res) : [num] "m"(num));
asm("movq %1, %0" : "=r"(res) : "m"(num));
asm("movq %1, %0" : "=m"(res) : "m"(num));
asm("movq %1, %0" : "=r"(res) : "r"(num));

// 對應的彙編代碼, 只保留asm表達式中的代碼
# 13 "asm.c" 1
        movq -16(%rbp), %rax  // asm-1
 # 0 "" 2
/NO_APP

/APP
 # 15 "asm.c" 1
        movq -16(%rbp), %rax  // asm-2
 # 0 "" 2
/NO_APP

/APP
 # 17 "asm.c" 1
        movq -16(%rbp), -8(%rbp)  // asm-3
 # 0 "" 2
/NO_APP

/APP
 # 19 "asm.c" 1
        movq %rax, %rax  // asm-4
 # 0 "" 2
/NO_APP
  1. 使用名稱替換和数字替換效果一樣,見 asm-1 和 asm-2
  2. 約束的用法,這裏使用比較簡單通用的的兩種情況,r 為通過寄存器尋址操作,m 通過內存尋址操作,所以看到當約束了 r 就對應寄存器的操作。
  3. 結果保存在 res 也就是 cvariablename 中

InputOperands

輸入操作數使C變量和表達式中的值可用於彙編代碼。

[ [asmSymbolicName] ] constraint (cexpression)
  • asmSymbolicName 和輸出列表的用法完全一致
  • constraint 約束不能使用 =+. 可以使用 “0”, 這表明在輸出約束列表中(從零開始)的條目,指定的輸入必須與輸出約束位於同一位置。
int64_t res = 3;
int64_t num = 1;
asm("addq %1, %0" : "=g"(res) : "0"(num));

// 輸入輸出位置相同
        movq    $3, -8(%rbp)
        movq    $1, -16(%rbp)
        movq    -16(%rbp), %rax
/APP
# 32 "asm.c" 1
        addq %rax, %rax
# 0 "" 2
/NO_APP
  • cexpression 可以不為左值,作為彙編表達式的輸入值即可

Clobbers

破壞列表,主要用於指示編譯器生成的彙編指令。

從asm表達式中看到輸出操作數中列出條目的更改編譯器是可以確定的,但內聯彙編代碼可能不僅對輸出進行了修改。 例如,計算可能需要其他寄存器,或者處理器可能會由於特定彙編程序指令而破壞寄存器的值。 為了將這些更改通知編譯器,在Clobber列表中列出這些會產生副作用的條目。 破壞列表條目可以是寄存器名稱,也可以是特殊的破壞列表項(在下面列出)。 每個內容列表條目都是一個字符串常量,用雙引號引起來並用逗號分隔。

  • 寄存器

      ```c
      asm volatile("movc3 %0, %1, %2"
              : /* No outputs. */
              : "r"(from), "r"(to), "g"(count)
              : "%rbx", "%rcx", "%rdx", "memory");
    
      /APP
      # 25 "asm.c" 1
              movc3 %rax, %r8, -72(%rbp)
      # 0 "" 2
      /NO_APP
      ```
    
      可以看到使用到了 rax 寄存器,然後修改程序在 Clobbers 增加 %rax, 結果如下
    
      ```c
      asm volatile("movc3 %0, %1, %2"
              : /* No outputs. */
              : "r"(from), "r"(to), "g"(count)
              : "%rax", "%rbx", "%rcx", "%rdx", "memory");
    
      /APP
      # 25 "asm.c" 1
              movc3 %r8, %r9, -72(%rbp)
      # 0 "" 2
      /NO_APP
      ```
      編譯器在產生的彙編代碼中就未使用 %rax 寄存器了。
  • 特殊破壞列表項
    – “cc”, 表示彙編代碼修改了標誌寄存器
    – “memory”, 為了確保內存中包含正確的值,編譯器可能需要在執行asm之前將特定的寄存器值刷新到內存中

編譯器為了破壞列表項的值受到破壞,當這些條目是寄存器時,不對其進行使用;為特殊參數時,重新刷新得到最新的值。

約束

  • 一些基礎的約束
約束名 說明
whitespace 空白字符被忽略
m 允許使用內存操作數,以及機器通常支持的任何類型的地址
o 允許使用內存操作數,但前提是地址是可偏移的
V 允許使用內存操作數,不可偏移的內存地址,與 “o’互斥
r 允許在通用寄存器中使用的寄存器操作數,其中可以指定寄存器,如 a(%rax), b(%rbx)
i 允許使用立即整數操作數
n 允許使用具有已知數值的立即整數操作數, ‘I’, ‘J’, ‘K’, … ‘P’ 更應該使用 n
F 允許使用浮點立即數
g 允許使用任何寄存器,內存或立即數整數操作數,但非通用寄存器除外
X 允許任何操作數, ‘0’, ‘1’, ‘2’, … ‘9’
p 允許使用有效內存地址的操作數
  • 標識符約束
標識符 說明
= 表示此操作數是由該指令寫入的:先前的值將被丟棄並由新數據替換
+ 表示該操作數由指令讀取和寫入
& 表示(在特定替代方法中)此操作數是早期指令操作數,它是在使用輸入操作數完成指令之前寫入的,故輸入操作數部分不能分配與輸出操作數相同的寄存器
% 表示該操作數與後續操作數的可交換指令

內核示例

  1. x86 的內存屏障指令。
// 避免編譯器的優化,聲明此處內存可能發生破壞
#define barrier() asm volatile("" ::: "memory")
// 在32位的CPU下,lock 指令為鎖總線,加上一條內存操作指令就達到了內存屏障的作用,64位的cpu已經有新增的 *fence 指令可以使用
// mb() 執行一個內存屏障作用的指令,為指定CPU操作;破壞列表聲明 cc memory 指示避免編譯器進行優化
#ifdef CONFIG_X86_32
#define mb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "mfence", \
                                X86_FEATURE_XMM2) ::: "memory", "cc")
#define rmb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "lfence", \
                                X86_FEATURE_XMM2) ::: "memory", "cc")
#define wmb() asm volatile(ALTERNATIVE("lock; addl $0,-4(%%esp)", "sfence", \
                                X86_FEATURE_XMM2) ::: "memory", "cc")
#else
#define mb()    asm volatile("mfence":::"memory")
#define rmb()   asm volatile("lfence":::"memory")
#define wmb()   asm volatile("sfence" ::: "memory")
#endif
  1. x86 下獲取 current 的值
DECLARE_PER_CPU(struct task_struct *, current_task);

#define this_cpu_read_stable(var)   percpu_stable_op("mov", var)

static __always_inline struct task_struct *get_current(void)
{
        return this_cpu_read_stable(current_task);
}

#define percpu_stable_op(op, var)           \
({                          \
        typeof(var) pfo_ret__;              \
        switch (sizeof(var)) {              \
        case 8:                     \
                asm(op "q "__percpu_arg(P1)",%0"    \
                : "=r" (pfo_ret__)          \
                : "p" (&(var)));            \
                break;                  \
        }                       \
        pfo_ret__;                  \
})

current_task 為一個 struct task_struct 類型的指針,追蹤宏調用,在x86-64 下命中了 case 8: 的彙編代碼, 展開的代碼為

asm("mov" "q ""%%""gs" ":" "%" "P1"",%0" : "=r" (pfo_ret__) : "p" (&(current_task)));
// 變換一下為
asm("movq %%gs:%P1, %0" : "=r"(pfo_ret__) : "p"(&(current_task)));

這行代碼的含義為將 約束輸入部分必須為有效的地址(p約束), 將CPU id(通過段寄存器gs和偏移通過GDT得到,這裏後文分析了)通過寄存器(r約束)賦值給 pfo_ret__.

參考

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

基於cookie的用戶登錄狀態管理

cookie是什麼

先來花5分鐘看完這篇文章:

看完上文,相信大家對cookie已經有了一個整體的概念,我再強調一下,cookie是一個客戶端概念,它是存儲在瀏覽器本地的一小段文本(通常由服務器來生成這段文本)。

cookie的作用

如上文所說,cookie有許多作用,如會話狀態管理,個性化設置,瀏覽器行為跟蹤,客戶端數據的存儲等等。本篇文章就來講講基於cookie的用戶登錄狀態管理。

插一句哈,一般提到cookie,還會有一個叫session的傢伙和它一起出現,下篇文章我會講到它,以及兩者的區別。

cookie的產生過程

如上圖所示,客戶端攜帶賬號和密碼向服務器發起請求,服務器在校驗通過後,通過HTTP Respose Header中的Set-Cookie頭部,將一小段文本寫入客戶端瀏覽器,在以後的每個客戶端HTTP Request Header的Cookie頭部中會自動攜帶這段文本。

基於cookie的用戶登錄狀態管理

下面我基於golang和gin框架(中間件使用比較舒服)來簡單的實現一個基於cookie的用戶登錄狀態管理demo

package main

import (
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    r.GET("/login", Login)
    
    // 需要登陸保護的
    auth := r.Group("")
    auth.Use(AuthRequired())
    {
        auth.GET("/me", UserInfo)
        auth.GET("/logout", Logout)
    }

    r.Run("localhost:9000")
}

// 登陸
func Login(c *gin.Context) {
    // 為了演示方便,我直接通過url明文傳遞賬號密碼,實際生產中應該用HTTP POST在body中傳遞
    userID := c.Query("user_id")
    password := c.Query("password")

    // 用戶身份校驗(查詢數據庫)
    if userID == "007" && password == "007" {
        // 生成cookie
        expiration := time.Now()
        expiration = expiration.AddDate(0, 0, 1)
        // 實際生產中我們可以加密userID
        cookie := http.Cookie{Name: "userID", Value: userID, Expires: expiration}
        http.SetCookie(c.Writer, &cookie)

        c.JSON(http.StatusOK, gin.H{"msg": "Hello " + userID})
        return
    }
    c.JSON(http.StatusBadRequest, gin.H{"msg": "賬號或密碼錯誤"})
}

// 檢測是否登陸的中間件
func AuthRequired() gin.HandlerFunc {
    return func(c *gin.Context) {
        cookie, _ := c.Request.Cookie("userID")
        if cookie == nil {
            c.JSON(http.StatusUnauthorized, gin.H{"msg": "請先登陸"})
            c.Abort()
        }
        // 實際生產中應校驗cookie是否合法
        c.Next()
    }
}

// 查看用戶個人信息
func UserInfo(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"msg": "007的個人頁面"})
}

// 退出登陸
func Logout(c *gin.Context) {
    // 設置cookie過期
    expiration := time.Now()
    expiration = expiration.AddDate(0, 0, -1)
    cookie := http.Cookie{Name: "userID", Value: "", Expires: expiration}
    http.SetCookie(c.Writer, &cookie)

    c.JSON(http.StatusOK, gin.H{"msg": "退出成功"})
}

我們來看具體的演示流程和效果:

如下圖所示,當我們退出后再去嘗試訪問個人頁面時,會出現401沒有權限的錯誤。

上述例子的缺點

先來說說上面的demo存在的問題吧,我們的退出登錄函數本質是設置了一個過期了的cookie來覆蓋以前發送給用戶的正常cookie。

但是,這兒存在着一個重大的安全問題。如果用戶將之前未過期的正常cookie記錄下來(即本例子中的userID=007),即使調用了我們的logout接口,只要用戶自己手動輸入之前未過期的正常cookie,也是可以通過服務器的驗證。

而且,最重要的是,我們無法讓其失效,因為cookie的過期刪除機制是由瀏覽器來控制的,但是當用戶記錄了cookie中的哪段文本后,在cookie到期后,瀏覽器只能刪除存在於瀏覽器中的cookie,對用戶自己記錄下來的cookie確無能為力,也就是說這段cookie永遠有效。(後面我們會講一種叫json web token的技術,可以做到讓我們簽發的憑證自帶過期機制,而不依賴瀏覽器)

當然,有同學會說,我們可以在服務器存儲一份有效的cookie列表,在用戶退出登錄后,從有效列表中刪除對應的cookie,這種在服務端維護用戶狀態的機制本質是session的思想,我們後面會講基於session的用戶登錄狀態管理。

再來說說cookie別的缺點:

當然這個我們通過設置cookie的屬性為HttpOnly,來禁止JavaScript讀取cookie值,可以起到一定的防護作用。

當然,cookie也是有優點的,我們把用戶的登錄狀態保存在客戶端,這樣就不需要每一次去訪問數據庫來檢測用戶是否登錄,減少了系統的IO開銷。

最後

本文希望通過一個不是很完美的demo來講述基於cookie的用戶登錄狀態管理,下期我們來講講session。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

台灣藝術家黃瑞芳 獲吐瓦魯任命「氣候緊急大使」

整理:彭瑞祥(環境資訊中心記者)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

京津冀將規劃一體化電動汽車公共充電網絡

中國京津冀等三地於7月30日簽署了協議,將共同開發京津冀區域的一體化電動汽車公共充電網絡,目標在2020年完工實施。此案將涵蓋電動車發展以及充電設備標準的設立、充電設備之量化,相關國家政策也會陸續制定提出。

中國大陸的電動車產業發展迅速,在「十二五」相關計畫之中就曾規劃2015年底要在全中國安裝40萬個電動車充電樁、2000個充換電站,但此一目標並沒有達成。究其原因,除了新能源電動車仍在發展階段之外,充電設備的標準尚未統一、社會資本進入難、營利模式單一等,都是使充電設備安裝計畫無法落實的原因。

據中國媒體《經濟參考報》指出,在京津冀三地簽署共同發展合約後,國家級的電動車充電標準文件《電動汽車充電基礎設施指南》以及《充電基礎設施指導意見》等規章也會陸續提出,這規章將具體規劃充電設備的數量:到2020年時,國內充換電站的數量目標1.2萬個,充電樁450萬個;此外,電動車與充電設施的比例也預計將從現在的4:1提升到1:1左右。在如此龐大的數量規劃下,中國充電市場的規模預計會超過人民幣1000億元。

不過,市場規模擴張的前提仍是充電設施建設能如期推行,而充電設施之建設推行則仰賴技術標準化,例如充電插槽、通訊協議等,以確保不同品牌的電動車都能一體適用。

而在盈利與資本進入困難等問題方面,政策保障將可為市場資本創造可靠的入口,進而加強獲利幅度。

中國國內的充電產業有越來越多國企、民企接連投入,例如青島特來電公司計畫到2015年底在全國40個城市建設7至10萬個充電設備,投資超過人民幣10億元,希望三年內能占全國市場50%以上。具有外資背景的富電科技公司也在今年一月在北京華貿中心落成中國首個核心商圈光伏智能充電站。車用充電業界也開始有創業者投入。

(照片來源:)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

軟件測試(開發)工程師的核心競爭力是什麼?

1. 測試行業正在發生變化

在互聯網新趨勢和新要求的變革推動下,測試行業也在不知不覺中發生着非常大的改變,從早些年的懵懂發展,大家摸着石頭過河,到大多高校設立軟件測試專業,再到近幾年各種測試培訓盛行。如果說早期軟件測試行業還是一個風口,隨着不斷地轉行人員以及畢業的大學生瘋狂地湧入軟件測試行業,目前軟件測試行業“缺口”已經基本飽和,最基礎的功能測試的崗位需求已經越來越少了。測試的進入門檻,也從真正零基礎,到現在的要求具備專業的計算機專業能力(包括不限於編程能力),軟件測試在企業的受重視程度,特別是互聯網行業,也從可有可無,到不可或缺。

2. 行業人員分佈呈現兩極勢態

測試行業不斷髮展,行業已經呈現出嚴重的兩極分化勢態,一邊是資深的測試大牛,屬於全棧複合型人才,但這一類行業中人員占的比例較為稀少。一是由於行業原因,代碼能力強,有架構經驗的人員一般都在開發部門;二是要求高,資深測試開發工程師不僅要精通測試相關的技能,還要會前端設計,服務端開發等等,幾乎是全棧工程師;而做程序的人員一般精通一點或是幾點的較多,從前到后全都能上的越來越少。另一邊是測試小白,即便是有些在測試行業中已經摸爬滾打了幾年,但仍然有很多測試人員還是停留在只會業務功能測試的這個階段。而針對這類型的測試從業人員,除了一些安於現狀的除外,大多數人其實都還是想好好學習,想進步的只是不知道學習方向,或者學習不得其法。

 

3. 企業需要更多高端綜合人才

但不管是屬於哪一種,對於企業而言,想快速發展自己的業務,必須有一個強大的測試團隊來保證質量,通過一系列的質量保障手段,如引入CI,CD以及其他的手段來促進項目的快速迭代與交付。這就要求相關的測試工程師要能從多方面來考慮設計和解決問題,不僅要考慮項目的實施成本,還要考慮參与的測試,開發,產品甚至用戶等人員,同時要與公司發展的前景及方向相切合,並能很好地為之服務。提供這類能力的測試人才在公司都是較為吃香的,每年的找工作季節也就那麼幾個人會進入人才市場流通,而且很快就能找到工作,這也是每個測試人員的努力方向,只有具備了相應的價值實力,才有資格向企業要求你期望的回報

 

4.企業招人與求職者供求總是難以匹配

很多同學抱怨,企業招人為什麼要求越來越高,除了學歷(本科以上),還要求年齡(35內),以及項目經驗,太難太難 。其實,企業也挺苦惱的:招幾個適合的人選太難了 ,這就是所謂的「供需關係」失調了 。大批測試從業者找不到工作,大量企業找不到適合的人選 。

而造成不匹配、供需關係失調的最核心的問題歸根到底還是聚焦於能力要求不匹配

那麼測試人員核心技能或者說測試人員的核心競爭力到底有哪些? 測試人員應該思考這個問題、企業用人單位也應該要思考需要什麼樣的測試人員?相信大家面試求職時或多或少都會有這種感覺,企業在招聘時,要求會各種框架、各種編程語言、各種工具的使用。那在我們學會了測試技術、測試工具的使用,最後核心競爭力到底聚焦在哪些方面?

 

5. 你的核心競爭力是什麼?

提到在軟件測試這個行業,你的核心競爭力是什麼?這是個非常有意思的話題,就像我們經常說的“團隊中的價值問題”,你經常看到測試人員自己在想,我們的價值在哪裡、是什麼?但我們很少看到軟件的開發人員或者架構師,或者運維團隊去問這樣一個問題,要去找自己的價值。這是因為測試人員對這個價值本身是不太確定的,那麼這個價值本身不確定,就會帶來的一系列的問題。

在早期軟件行業中,會發現存在一個普遍的現象,有些大學的本科,或者研究生畢業,他們去面試工作的時候就會發現,面試下來的是代碼能力可能不是太好,這種情況下公司會問你願不願意去做測試?但隨着現在這個時代的變革,現在的軟件測試工程師,他的知識面,以及他需要掌握的內容已經遠遠超過了之前,可以說他的知識面是遠遠超過開發的,比如在一些技術的面上,以及對產品的理解上。

那麼這種情況下,我們再去提一個優秀的軟件測試工程師的核心價值,我們可以很自信地說,測試工程師是一個不可被替代的,並且是一個專業細分化的領域。像早年的時候,我們談到測試,就是軟件測試,沒有細分市場,但現在你去談測試,測試現在的領域太多了,除了傳統意義上的,基於業務領域的測試,然後還有測試開發。

 

6. 企業為什麼不願給你開高薪?

經常會有從業者諮詢我:“怎麼轉行到測試開發崗位?測試開發崗位怎麼入手?測試開發崗位到底是做什麼的?需要掌握哪些知識 ?”

其實啊,問這些問題的時候,你可能就不太適合此崗位。或者你只是聽說測試開發工資高、奔着薪資來的,也許你完全不適合 。

正如在之前介紹測試開發的文章 : 中提到過隨着現在測試開發崗在各個公司的設定,且測試開發崗一般會頂着“薪資高”的頭銜(至少在測試這個領域,測試開發的薪資普遍都要比業務手工測試高上許多),越來越多的手工測試人員,都急於想轉崗到測試開發,但需不知往往只是看到了測試開發崗的薪資高,但卻忽略了最重要的一點(那些拿高薪的人付出的努力同樣也是比你多)!我們不妨先看看下面幾則同行人的心聲。(是否曾及何時,正在讀文的你也是這麼認為的?)

  • 很多QQ群、微信群的測試同行經常在抱怨,平日測試工作乾的很苦逼,活沒少干,加班也沒少加,但工資、獎金卻比其它崗(比如開發)要拿的少。
  • 測試工作做了好幾年了,但去外面求職的時候,屢屢碰壁,總得拿不到自己滿意的薪資Offer。
  • 認為測試崗位沒有“錢”途、工作內容做的沒有意義,不如趁早轉開發、產品。

 

之所以行業中會有許多從業人員有上述幾點心聲,最核心的問題點還是認為自己工作乾的活所得到的薪資待遇和自己希望得到的回報無法相匹配上。正如馬雲之前說過,企業員工離職的原因,歸根結底只有兩個:1、錢沒給夠。2、平台無法施展才能,覺得委屈了

 

我相信絕大多數人,都是“倒”在了第一點原因上。那為什麼企業開的薪資就總是無法達到“大多數從業人員”的要求呢?難道企業開不起薪資?但身在同一個公司,為何又存在其它崗位“測試開發”、“開發”薪資高這一說法?這顯然並不是企業開不起薪資,而是企業認為TA所能幫助企業帶來的價值只值這麼多。

 

7. 對高薪崗位的誤解

不論是“測試開發”或者是“開發”,頂着“薪資高”這一普遍說法,其中大多數對這個說法還是存在誤解的,並不是所謂的“崗位薪資論”,認為做了這個崗位,就一定有高的薪資,試想一下,同樣有很多開發人員,薪資不見的就比測試牛人高。而那些之所以有着“高薪崗位的人”,是因為他們所具備的能力以及能為公司帶來的價值也是越高的。因此,`高薪!= 崗位`,而**應該是高薪要等於與之匹配的能力和能為企業帶來的等同價值**。

這一觀點,恰好也回應了上述所提到的,現在越來越多的手工測試人員都想轉行測試開發。但轉行到測試開發並不是關鍵,如果能力沒有轉變,只是崗位的頭銜轉變了,即便給你安排一個測試開發或開發的頭銜,但你的能力還只是在干一些不痛不癢的工作,那麼企業仍然是不可能會為你買單的。之所有測試開發有着高薪的說法,是由於現在企業對測試開發的綜合能力已經不亞於開發,他們的技術能力和解決業務問題的能力在某些方面甚至要強於開發。因此企業肯為這些人付出高薪的回報。

我想對那些想轉崗或者埋怨自己工資低的從業人員,奉切一句:轉崗不是最終目的,提升自身能力才是根本。如果你的能力足夠出眾,能你團隊、企業帶來的價值已經超出測試所需要提供的,即便只是頂着業務測試的頭銜,我相信,企業仍然肯為你付出相應的高回報。

 

8. 如何打造個人核心競爭力

那些想拿高薪或者是想轉崗成為測試開發的同學,需要做的應該是要不斷提升自身能力和價值點,這些價值點立足在團隊、公司無非就是兩類能力:1.綜合技術能力、2.幫助產品業務解決問題的能力。

1. 提升綜合技術能力,說到技術,第一關:開發語言(不管是Python,還是Java,真的無所謂,先搞懂一個再說) 。

先能獨立開發一套可用的東西。至於你寫的代碼高性能、高可用,先可以放放 。但至少得通過擼代碼,實現業務方需求吧 ?

很多測試同學問,到底學Python還是學Java ?半年後,你去問他學的咋樣的,他可能還在那糾結:“到底是學Python還是學Java ?”的問題,根本就沒開始學。

“學習這事,道理都懂,就是缺行動。”,雖然這句話,看起來像廢話,但事實如此。

很多時候,看着那些:“知道自己能力有問題、想學點啥東西、到處諮詢他人應該學啥、得到答案后、依然半年沒行動”的(別笑,看文章的你,也許就是)。

否則,怎麼可能會出現:在市場上,想招一些靠譜的從業者,那麼難 。看到很多公司,耗時幾個月招不到適合的人,雖然這裡有公司的原因,但求職者能力不符合,是很大一部分原因 。

行業在發展,一直守着“自己那點業務知識、測試流程、幾年前的工具”的同學,太多 。借用之前的觀點,定期出來面試聊聊,你會發現,你根本找不到合適的工作 。

如果還在糾結學啥開發語言的,別糾結,此刻、現在,開始,學Python 。

Python易入手,簡單,好用 。而且,如果不做測試開發,通過Python也可以玩轉各種自動化測試。

 

OK ,如上內容,是對測試(開發)工程師核心競爭力的一些看法,摘自本人公眾號中的一部分篇幅內容,僅代表個人觀點 。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

南投搬家前需注意的眉眉角角,別等搬了再說!