国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

更改網(wǎng)站的布局欒城seo整站排名

更改網(wǎng)站的布局,欒城seo整站排名,創(chuàng)建公司策劃書,那種系統(tǒng)做網(wǎng)站比較好這里是 第三篇:用 OpenGL 實現(xiàn)高斯模糊。我們分別在 iOS 和 Android 平臺實現(xiàn)了用 OpenGL 對圖像進行高斯模糊處理并渲染出來。效果圖如下: 本文福利, 免費領(lǐng)取C音視頻學習資料包、技術(shù)視頻/代碼,內(nèi)容包括(音視頻開發(fā)&…

這里是 第三篇:用 OpenGL 實現(xiàn)高斯模糊。我們分別在 iOS 和 Android 平臺實現(xiàn)了用 OpenGL 對圖像進行高斯模糊處理并渲染出來。效果圖如下:

?本文福利, 免費領(lǐng)取C++音視頻學習資料包、技術(shù)視頻/代碼,內(nèi)容包括(音視頻開發(fā),面試題,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,編解碼,推拉流,srs)↓↓↓↓↓↓見下面↓↓文章底部點擊免費領(lǐng)取↓↓

高斯模糊是一種柔和模糊的圖像效果,模糊后的圖像可以被更復雜的算法用來產(chǎn)生例如炫光、景深、熱浪或者毛玻璃的效果。本文將會給大家介紹高斯模糊的數(shù)學原理,以及用 OpenGL 完成高斯模糊的代碼實現(xiàn)。

1、高斯模糊基礎(chǔ)知識

高斯模糊(Gaussian Blur),也叫高斯平滑,是在圖像處理中廣泛使用的處理效果,通常用它來減少圖像噪聲以及降低細節(jié)層次。因為其視覺效果就像是經(jīng)過一個半透明屏幕在觀察圖像,所以常用于生成毛玻璃效果。

從數(shù)學的角度來看,圖像的高斯模糊過程就是圖像與正態(tài)分布做卷積,由于正態(tài)分布又叫作高斯分布,所以這項技術(shù)就叫作高斯模糊。

1.1、基本原理

讓我們先看一個直觀的例子來理解模糊這個概念。

上圖中,中間點是 2,周邊點都是 1。

假如現(xiàn)在我們想讓中間點和周圍的點數(shù)值上更加接近來達成我們模糊中間點和周圍點邊界的目的。我們可以讓中間點取周圍點的平均值,那么中間點就會從 2 變成 1,中間點就會靠近周圍的值,這就是數(shù)值上的平滑,也就是模糊。

我們將這個想法應用到圖像上,對圖像中的每一個像素點,取周圍像素的平均值,自然而然就會讓這幅圖產(chǎn)生模糊效果。

當我們?nèi)≈車c的時候,所參考的范圍呈現(xiàn)一個圓形,圓形半徑越大,模糊效果就會越強烈。

如果使用簡單平均,顯然不是很合理,因為圖像都是連續(xù)的,越靠近的點關(guān)系越密切,越遠離的點關(guān)系越疏遠。因此,加權(quán)平均更合理,距離越近的點權(quán)重越大,距離越遠的點權(quán)重越小。

高斯模糊就是一種加權(quán)平均的模糊效果。

1.2、高斯函數(shù)的數(shù)學表達

正態(tài)分布的密度函數(shù)叫做高斯函數(shù)(Gaussian function)。

在圖形上,正態(tài)分布是一種鐘形曲線,越接近中心,取值越大,越遠離中心,取值越小。計算平均值的時候,我們只需要將中心點作為原點,其他點按照其在正態(tài)曲線上的位置,分配權(quán)重,就可以得到一個加權(quán)平均值。

因為我們處理的是圖像,而圖像可以表示為二維矩陣,其中每個元素為 ARGB 像素值,因此我們在這里需要延伸到二維高斯函數(shù)。

高斯函數(shù)的一維形式是:

高斯函數(shù)的二維形式是:

?

假如目前有一張寬高為 1024x1024 的圖像,我們使用上述所說的方法對這個圖像上的每個點計算二維正態(tài)分布的加權(quán),參考當前坐標附近距離半徑為 33 的所有像素。那么可以得知,我們需要進行的計算次數(shù)為 1024 * 1024 * 33 * 33 ≈ 11.4 億次,這顯然是一個不可接受的算法,我們需要對算法的效率進行優(yōu)化。

因為二維高斯函數(shù)具有分離性,所以二維高斯函數(shù)可以拆分為兩個一維高斯函數(shù)來計算(證明過程參考:二維高斯卷積核拆分成兩個一維的高斯卷積核[1]),所以我們可以將算法優(yōu)化為先計算水平方向的加權(quán)函數(shù)再計算垂直方向的加權(quán)函數(shù)。這樣我們的算法計算量就從之前的 1024 * 1024 * 33 * 33 ≈ 11.4 億次 下降為 1024 * 1024 * 33 * 2 ≈ 6900 萬次。

所以,我們的算法優(yōu)化為水平方向運行一次著色器后再在垂直方向運行一次著色器。

2、iOS Demo

2.1、渲染模塊

渲染模塊與 OpenGL 渲染視頻 中講到的一致,最終是封裝出一個渲染視圖 KFOpenGLView 用于展示最后的渲染結(jié)果。這里就不再細講,只貼一下主要的類和類具體的功能:

  • KFOpenGLView:使用 OpenGL 實現(xiàn)的渲染 View,提供了設(shè)置畫面填充模式的接口和渲染一幀紋理的接口。
  • KFGLFilter:實現(xiàn) shader 的加載、編譯和著色器程序鏈接,以及 FBO 的管理。同時作為渲染處理節(jié)點,提供給了接口支持多級渲染。
  • KFGLProgram:封裝了使用 GL 程序的部分 API。
  • KFGLFrameBuffer:封裝了使用 FBO 的 API。
  • KFTextureFrame:表示一幀紋理對象。
  • KFFrame:表示一幀,類型可以是數(shù)據(jù)緩沖或紋理。
  • KFGLTextureAttributes:對紋理 Texture 屬性的封裝。
  • KFGLBase:定義了默認的 VertexShader 和 FragmentShader。

2.2、高斯模糊 Shader 實現(xiàn)

我們使用 KFGLFilter 為它設(shè)置高斯模糊的 Shader 來實現(xiàn)我們高斯模糊效果,對應的頂點著色器和片段著色器的代碼如下:

KFGLGaussianBlur.h

#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN#define STRINGIZE(x) #x
#define STRINGIZE2(x) STRINGIZE(x)
#define SHADER_STRING(text) @ STRINGIZE2(text)extern NSString *const KFGLGaussianBlurVertexShader;
extern NSString *const KFGLGaussianBlurFragmentShader;NS_ASSUME_NONNULL_END

KFGLGaussianBlur.m

#import "KFGLGaussianBlur.h"NSString *const KFGLGaussianBlurVertexShader = SHADER_STRING
(attribute vec4 position; // 通過 attribute 通道獲取頂點信息。4 維向量。attribute vec4 inputTextureCoordinate; // 通過 attribute 通道獲取紋理坐標信息。4 維向量。varying vec2 textureCoordinate; // 用于 vertex shader 和 fragment shader 間傳遞紋理坐標。2 維向量。const int GAUSSIAN_SAMPLES = 9; // 被參考的點數(shù)目。uniform float wOffset; // 水平方向單位偏移。Offset 越大結(jié)果越模糊。uniform float hOffset; // 垂直方向單位偏移。Offset 越大結(jié)果越模糊。varying vec2 blurCoordinates[GAUSSIAN_SAMPLES]; // 被參考點的紋理坐標數(shù)組,將在 vertex shader 和 fragment shader 間傳遞。2 維向量數(shù)組。void main(){gl_Position = position;textureCoordinate = inputTextureCoordinate.xy; // 將通過 attribute 通道獲取的紋理坐標數(shù)據(jù)中的 2 維分量傳給 fragment shader。int multiplier = 0;vec2 blurStep;vec2 singleStepOffset = vec2(hOffset, wOffset);for (int i = 0; i < GAUSSIAN_SAMPLES; i++){multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2)); // 每一個被參考點距離當前紋理坐標的偏移乘數(shù)blurStep = float(multiplier) * singleStepOffset; // 每一個被參考點距離當前紋理坐標的偏移blurCoordinates[i] = inputTextureCoordinate.xy + blurStep; // 每一個被參考點的紋理坐標}}
);NSString *const KFGLGaussianBlurFragmentShader = SHADER_STRING
(varying highp vec2 textureCoordinate; // 從 vertex shader 傳遞來的紋理坐標。uniform sampler2D inputImageTexture; // 通過 uniform 通道獲取紋理信息。2D 紋理。const lowp int GAUSSIAN_SAMPLES = 9; // 被參考的點數(shù)目。varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES]; // 從 vertex shader 傳遞來的被參考點的紋理坐標數(shù)組。void main(){lowp vec4 sum = vec4(0.0);// 根據(jù)距離當前點距離遠近分配權(quán)重。分配原則越近權(quán)重越大。sum += texture2D(inputImageTexture, blurCoordinates[0]) * 0.05;sum += texture2D(inputImageTexture, blurCoordinates[1]) * 0.09;sum += texture2D(inputImageTexture, blurCoordinates[2]) * 0.12;sum += texture2D(inputImageTexture, blurCoordinates[3]) * 0.15;sum += texture2D(inputImageTexture, blurCoordinates[4]) * 0.18;sum += texture2D(inputImageTexture, blurCoordinates[5]) * 0.15;sum += texture2D(inputImageTexture, blurCoordinates[6]) * 0.12;sum += texture2D(inputImageTexture, blurCoordinates[7]) * 0.09;sum += texture2D(inputImageTexture, blurCoordinates[8]) * 0.05;// 加權(quán)。gl_FragColor = sum;}
);

2.3、圖像轉(zhuǎn)紋理

我們還需要實現(xiàn)一個 KFUIImageConvertTexture 類用于實現(xiàn)圖片轉(zhuǎn)紋理,之后再對紋理使用 OpenGL 進行處理。代碼如下:

KFUIImageConvertTexture.h

#import <Foundation/Foundation.h>
#import <OpenGLES/EAGL.h>
#import <UIKit/UIKit.h>
#import "KFTextureFrame.h"@interface KFUIImageConvertTexture : NSObject+ (KFTextureFrame *)renderImage:(UIImage *)image;@end

KFUIImageConvertTexture.m

#import "KFUIImageConvertTexture.h"@implementation KFUIImageConvertTexture+ (KFTextureFrame *)renderImage:(UIImage *)image {CGImageRef cgImageRef = [image CGImage];GLuint width = (GLuint)CGImageGetWidth(cgImageRef);GLuint height = (GLuint)CGImageGetHeight(cgImageRef);CGRect rect = CGRectMake(0, 0, width, height);CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();void *imageData = malloc(width * height * 4);CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);CGColorSpaceRelease(colorSpace);CGContextClearRect(context, rect);CGContextDrawImage(context, rect, cgImageRef);glEnable(GL_TEXTURE_2D);GLuint textureID;glGenTextures(1, &textureID);glBindTexture(GL_TEXTURE_2D, textureID);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);// 結(jié)束后要做清理glBindTexture(GL_TEXTURE_2D, 0); // 解綁CGContextRelease(context);free(imageData);KFTextureFrame *inputFrame = [[KFTextureFrame alloc] initWithTextureId:textureID textureSize:CGSizeMake(width, height) time:kCMTimeZero];return inputFrame;
}

2.4、展示高斯模糊渲染結(jié)果

我們在一個 ViewController 串聯(lián)對圖片進行高斯模糊處理的邏輯,并展示最后的效果。代碼如下:

#import "KFGaussianBlurViewController.h"
#import "KFUIImageConvertTexture.h"
#import "KFOpenGLView.h"
#import "KFGLFilter.h"
#import "KFGLGaussianBlur.h"@interface KFGaussianBlurViewController ()
@property (nonatomic, strong) KFOpenGLView *glView;
@property (nonatomic, strong) KFUIImageConvertTexture *imageConvertTexture;
@property (nonatomic, strong) EAGLContext *context;
@property (nonatomic, strong) KFGLFilter *verticalGaussianBlurFilter;
@property (nonatomic, strong) KFGLFilter *horizonalGaussianBlurFilter;
@end@implementation KFGaussianBlurViewController#pragma mark - Property
- (EAGLContext *)context {if (!_context) {_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];}return _context;
}- (KFUIImageConvertTexture *)imageConvertTexture {if (!_imageConvertTexture) {_imageConvertTexture = [[KFUIImageConvertTexture alloc] init];}return _imageConvertTexture;
}- (KFGLFilter *)verticalGaussianBlurFilter {if (!_verticalGaussianBlurFilter) {_verticalGaussianBlurFilter = [[KFGLFilter alloc] initWithCustomFBO:NO vertexShader:KFGLGaussianBlurVertexShader fragmentShader:KFGLGaussianBlurFragmentShader];[_verticalGaussianBlurFilter setFloatUniformValue:@"hOffset" floatValue:0.00390625f];}return _verticalGaussianBlurFilter;
}- (KFGLFilter *)horizonalGaussianBlurFilter {if (!_horizonalGaussianBlurFilter) {_horizonalGaussianBlurFilter = [[KFGLFilter alloc] initWithCustomFBO:NO vertexShader:KFGLGaussianBlurVertexShader fragmentShader:KFGLGaussianBlurFragmentShader];[_horizonalGaussianBlurFilter setFloatUniformValue:@"wOffset" floatValue:0.00390625f];}return _horizonalGaussianBlurFilter;
}#pragma mark - Lifecycle
- (void)viewDidLoad {[super viewDidLoad];[self setupUI];[self applyGaussianBlurEffect];
}- (void)viewWillLayoutSubviews {[super viewWillLayoutSubviews];self.glView.frame = self.view.bounds;
}- (void)setupUI {self.edgesForExtendedLayout = UIRectEdgeAll;self.extendedLayoutIncludesOpaqueBars = YES;self.title = @"Gaussian Blur";self.view.backgroundColor = [UIColor whiteColor];// 渲染 view。_glView = [[KFOpenGLView alloc] initWithFrame:self.view.bounds context:self.context];_glView.fillMode = KFGLViewContentModeFit;[self.view addSubview:self.glView];
}- (void)applyGaussianBlurEffect {[EAGLContext setCurrentContext:self.context];UIImage *baseImage = [UIImage imageNamed:@"KeyframeLogo"];KFTextureFrame *textureFrame = [KFUIImageConvertTexture renderImage:baseImage];// 垂直方向做一次高斯模糊。KFTextureFrame *verticalTexture = [self.verticalGaussianBlurFilter render:textureFrame];// 水平方向做一次高斯模糊。KFTextureFrame *horizonalTexture = [self.horizonalGaussianBlurFilter render:verticalTexture];[self.glView displayFrame:horizonalTexture];[EAGLContext setCurrentContext:nil];
}@end

通過上面的代碼,可以看到我們是用 KFGLFilter 來封裝一次 OpenGL 的處理節(jié)點,它可以接收一個 KFTextureFrame 對象,加載 Shader 對其進行渲染處理,處理完后輸出處理后的 KFTextureFrame,然后可以接著交給下一個 KFGLFilter 來處理,就像一條渲染鏈。

這里我們把高斯模糊用到的二維高斯卷積核拆成兩個一維的高斯卷積核,所以是分別做了一次垂直方向和一次水平風向的處理。

3、Android Demo

Android 實現(xiàn)高斯模糊的 Demo 我們是在 OpenGL 渲染視頻 Demo 的基礎(chǔ)上在相機返回的視頻幀被渲染前增加了高斯模糊的處理。對應視頻采集模糊和視頻渲染模塊這里就不再細講,只貼一下主要的類和類具體的功能:

  • KFGLContext:負責創(chuàng)建 OpenGL 環(huán)境,負責管理和組裝 EGLDisplay、EGLSurface、EGLContext。
  • KFGLFilter:實現(xiàn) shader 的加載、編譯和著色器程序鏈接,以及 FBO 的管理。同時作為渲染處理節(jié)點,提供給了接口支持多級渲染。
  • KFGLProgram:負責加載和編譯著色器,創(chuàng)建著色器程序容器。
  • KFGLBase:定義了默認的 VertexShader 和 FragmentShader。
  • KFSurfaceView:KFSurfaceView 繼承自 SurfaceView 來實現(xiàn)渲染。
  • KFTextureView:KFTextureView 繼承自 TextureView 來實現(xiàn)渲染。
  • KFFrame:表示一幀,類型可以是數(shù)據(jù)緩沖或紋理。
  • KFRenderView:KFRenderView 是一個容器,可以選擇使用 KFSurfaceView 或 KFTextureView 作為實際的渲染視圖。

實現(xiàn)高斯模糊的頂點著色器代碼和片段著色器代碼如下:

public static String defaultGaussianVertexShader ="attribute vec4 position; \n" +"attribute vec4 inputTextureCoordinate; \n" +"varying vec2 textureCoordinate; \n" +"const int GAUSSIAN_SAMPLES = 9; \n" +"uniform float wOffset; \n" +"uniform float hOffset; \n" +"varying vec2 blurCoordinates[GAUSSIAN_SAMPLES]; \n" +"void main() \n" +"{ \n" +"  gl_Position = position; \n" +"  textureCoordinate = inputTextureCoordinate.xy; \n" +"  int multiplier = 0; \n" +"  vec2 blurStep; \n" +"  vec2 singleStepOffset = vec2(hOffset, wOffset); \n" +"  for (int i = 0; i < GAUSSIAN_SAMPLES; i++) \n" +"  { \n" +"    multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2)); \n" +"    blurStep = float(multiplier) * singleStepOffset; \n" +"    blurCoordinates[i] = inputTextureCoordinate.xy + blurStep; \n" +"  } \n" +"} \n" ;
public static String defaultGaussianFragmentShader ="varying highp vec2 textureCoordinate; \n" +"uniform sampler2D inputImageTexture; \n" +"const lowp int GAUSSIAN_SAMPLES = 9; \n" +"varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES]; \n" +"void main() \n" +"{\n" +"  lowp vec4 sum = vec4(0.0); \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[0]) * 0.05; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[1]) * 0.09; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[2]) * 0.12; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[3]) * 0.15; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[4]) * 0.18; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[5]) * 0.15; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[6]) * 0.12; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[7]) * 0.09; \n" +"  sum += texture2D(inputImageTexture, blurCoordinates[8]) * 0.05; \n" +"  gl_FragColor = sum; \n" +"} \n" ;

對 MainActivity 的改動則主要是在 KFVideoCaptureListener 的 onFrameAvailable 回調(diào)中增加對圖像幀做高斯模糊的處理邏輯,再進行渲染即可。代碼如下

public void onFrameAvailable(KFFrame frame) {mGLContext.bind();if (mVerticalGLFilter == null) {mVerticalGLFilter = new KFGLFilter(false, defaultGaussianVertexShader,defaultGaussianFragmentShader);mVerticalGLFilter.setFloatUniformValue("hOffset",0.00390625f);}if (mHoritizalGLFilter == null) {mHoritizalGLFilter = new KFGLFilter(false, defaultGaussianVertexShader,defaultGaussianFragmentShader);mHoritizalGLFilter.setFloatUniformValue("wOffset",0.00390625f);}KFFrame filterFrame = mVerticalGLFilter.render((KFTextureFrame)frame);KFFrame hFilterFrame = mHoritizalGLFilter.render((KFTextureFrame)filterFrame);mRenderView.render((KFTextureFrame) hFilterFrame);mGLContext.unbind();
}

可見,當我們用 KFGLFilter 將 OpenGL 渲染能力封裝起來,并可以像增加渲染處理節(jié)點一樣往現(xiàn)有渲染鏈中增加新的圖像處理功能時,相關(guān)改動就變得很方便了。

本文福利, 免費領(lǐng)取C++音視頻學習資料包、技術(shù)視頻/代碼,內(nèi)容包括(音視頻開發(fā),面試題,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,編解碼,推拉流,srs)↓↓↓↓↓↓見下面↓↓文章底部點擊免費領(lǐng)取↓↓

http://aloenet.com.cn/news/45599.html

相關(guān)文章:

  • 怎么給幼兒園做網(wǎng)站seo專業(yè)培訓機構(gòu)
  • 用css做網(wǎng)站菜單廣告多的網(wǎng)站
  • 版權(quán)申請網(wǎng)站磁力天堂
  • 網(wǎng)站開發(fā)現(xiàn)在主要用什么語言女教師遭網(wǎng)課入侵直播錄屏曝
  • 寧晉網(wǎng)站建設(shè)模板建站公司
  • 網(wǎng)站建設(shè)分金手指排名五鄭州網(wǎng)站制作選擇樂云seo
  • 網(wǎng)站建設(shè)源代碼網(wǎng)絡(luò)營銷的四個特點
  • 做logo有哪些網(wǎng)站2022年度關(guān)鍵詞
  • 古鎮(zhèn)中小企業(yè)網(wǎng)站建設(shè)如何找客戶資源
  • 建網(wǎng)站有域名和主機sem競價培訓班
  • 1688網(wǎng)站一起做網(wǎng)店關(guān)鍵詞提取工具app
  • 自己做的網(wǎng)站被舉報違反廣告法網(wǎng)上軟文發(fā)稿平臺
  • dw做網(wǎng)站的所有流程seo競價排名
  • 網(wǎng)站建設(shè)介紹seo網(wǎng)絡(luò)營銷外包
  • 公司門戶網(wǎng)站建設(shè)策劃書朔州網(wǎng)站seo
  • 國家工程建設(shè)質(zhì)量獎網(wǎng)站做一個網(wǎng)站要多少錢
  • 源碼搭建網(wǎng)站流程seo整站優(yōu)化系統(tǒng)
  • 網(wǎng)站怎么添加背景如何在百度上做產(chǎn)品推廣
  • 在線下單網(wǎng)站怎么做合肥seo外包平臺
  • 中國十大小說網(wǎng)站排名網(wǎng)絡(luò)平臺營銷
  • 做視頻教學網(wǎng)站推廣費用一般多少錢
  • 網(wǎng)站怎么收費的域名狀態(tài)查詢工具
  • 旅游網(wǎng)站開發(fā)社會的背景韶關(guān)seo
  • 淘寶網(wǎng)站怎么做鏈接地址友情鏈接價格
  • dede 更新網(wǎng)站地圖中國十大知名網(wǎng)站
  • 圖片在線設(shè)計網(wǎng)站如何建立獨立網(wǎng)站
  • 淄博哪個網(wǎng)站做房屋出賃好網(wǎng)上怎么做推廣
  • 廈門本地企業(yè)網(wǎng)站建設(shè)看seo
  • 建設(shè)銀行內(nèi)部網(wǎng)站網(wǎng)絡(luò)營銷的seo是做什么的
  • 做網(wǎng)站是怎樣賺錢的網(wǎng)站快速排名互點軟件