android實(shí)現(xiàn)人臉識(shí)別技術(shù)的示例代碼

1.前沿

專(zhuān)注于為中小企業(yè)提供成都網(wǎng)站制作、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)互助免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了數(shù)千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

人工智能時(shí)代快速來(lái)臨,其中人臉識(shí)別是當(dāng)前比較熱門(mén)的技術(shù),在國(guó)內(nèi)也越來(lái)越多的運(yùn)用,例如刷臉打卡,刷臉APP,身份識(shí)別,人臉門(mén)禁等。當(dāng)前的人臉識(shí)別技術(shù)分為WEBAPI和SDK調(diào)用兩種方式,WEBAPI需要實(shí)時(shí)聯(lián)網(wǎng),SDK調(diào)用可以離線(xiàn)使用。

本次使用的虹軟提供的人臉識(shí)別的SDK,此SDK也可根據(jù)不同應(yīng)用場(chǎng)景設(shè)計(jì),針對(duì)性強(qiáng)。包括人臉檢測(cè)、人臉跟蹤、人臉識(shí)別,即使在離線(xiàn)環(huán)境下也可正常運(yùn)行。

虹軟公司是一家具有硅谷背景的圖像處理公司,除了人臉技術(shù)以外,還有多項(xiàng)圖像及視頻處理技術(shù)。他們的雙攝像頭處理算法和人臉美化算法囊括了包括OPPO VIVO,SUMAMNG一系列手機(jī)廠商。

2.項(xiàng)目的目標(biāo)

我們需要實(shí)現(xiàn)一個(gè)人臉識(shí)別功能。簡(jiǎn)單來(lái)說(shuō),就是機(jī)的后置攝像頭,識(shí)別攝像頭中實(shí)時(shí)拍到的人臉信息,如果人庫(kù)注冊(cè)過(guò),則顯示識(shí)別后的人臉信息,如登記的名字;如果不在,提示未注冊(cè)。
這個(gè)功能具有多個(gè)應(yīng)用場(chǎng)景,比如,火車(chē)站或者打卡和門(mén)禁系統(tǒng)中。

3.人臉識(shí)別的過(guò)程

人臉識(shí)別包括兩個(gè)必備的過(guò)程,人臉注冊(cè)和實(shí)時(shí)識(shí)別。
人臉注冊(cè)是指把人臉的特征信息注冊(cè)到人臉信息庫(kù)中。人臉注冊(cè)的來(lái)源可以有很多種,比如

  1. 國(guó)家身份證庫(kù)
  2. 企業(yè)自建人臉識(shí)別庫(kù)
  3. 互聯(lián)網(wǎng)大數(shù)據(jù)庫(kù)

人臉特征提取是一個(gè)不可逆的過(guò)程,你無(wú)法從人臉特征信息還原一個(gè)人的臉部照片。

在線(xiàn)庫(kù)在使用時(shí),需要傳遞照片信息,或者提取圖像特征值,

離線(xiàn)的SDK相對(duì)安全,但是,在線(xiàn)的SDK通常提供更多的接入和調(diào)用方式,這個(gè)要結(jié)合實(shí)際情況來(lái)選擇。

4.定義并實(shí)現(xiàn)人臉庫(kù)的相關(guān)功能

如前面所述,我們希望定義自己 的人臉庫(kù),人臉庫(kù)在程序中使用List存儲(chǔ),在系統(tǒng)中保存為txt文件。

通過(guò)查詢(xún)引擎,可以知道人臉信息是保存在AFR_FSDKFace類(lèi)中的。這的主要結(jié)構(gòu)為

 public static final int FEATURE_SIZE = 22020;
 byte[] mFeatureData;

如果要進(jìn)行人臉注冊(cè),我們需要定義另外一個(gè)類(lèi)來(lái)把人臉信息和姓名關(guān)聯(lián)起來(lái)。

class FaceRegist {
    String mName;
    List<AFR_FSDKFace> mFaceList;

    public FaceRegist(String name) {
      mName = name;
      mFaceList = new ArrayList<>();
    }
  }

包含特征信息的長(zhǎng)度和內(nèi)容的byte數(shù)組。

我們把這些功能定義在類(lèi)FaceDB中。FaceDB需要包含引擎定義,初始化,把人臉信息保存在版本庫(kù)和從版本庫(kù)中讀出人臉信息這些功能

5.初始化引擎

為了程序結(jié)構(gòu)性考慮,我們將人臉識(shí)別相關(guān)的代碼獨(dú)立出來(lái)一個(gè)類(lèi)FaceDB,并定義必要的變量

public static String appid = "bCx99etK9Ns4Saou1EbFdC18xHdY9817EKw****";
public static String ft_key = "CopwZarSihp1VBu5AyGxfuLQdRMPyoGV2C2opc****";
public static String fd_key = "CopwZarSihp1VBu5AyGxfuLXnpccQbWAjd86S8****";
public static String fr_key = "CopwZarSihp1VBu5AyGxfuLexDsi8yyELdgsj4****";

String mDBPath;
List<FaceRegist> mRegister;
AFR_FSDKEngine mFREngine;
AFR_FSDKVersion mFRVersion;

定義有參數(shù)的構(gòu)造函數(shù)來(lái)初始化引擎

public FaceDB(String path) {
    mDBPath = path;
    mRegister = new ArrayList<>();
    mFRVersion = new AFR_FSDKVersion();
    mUpgrade = false;
    mFREngine = new AFR_FSDKEngine();
    AFR_FSDKError error = mFREngine.AFR_FSDK_InitialEngine(FaceDB.appid, FaceDB.fr_key);
    if (error.getCode() != AFR_FSDKError.MOK) {
      Log.e(TAG, "AFR_FSDK_InitialEngine fail! error code :" + error.getCode());
    } else {
      mFREngine.AFR_FSDK_GetVersion(mFRVersion);
      Log.d(TAG, "AFR_FSDK_GetVersion=" + mFRVersion.toString());
    }
  }

定義析構(gòu)函數(shù)釋放引擎占用的系統(tǒng)資源

public void destroy() {
    if (mFREngine != null) {
      mFREngine.AFR_FSDK_UninitialEngine();
    }
  }

6.實(shí)現(xiàn)人臉增加和讀取功能

通常人臉庫(kù)會(huì)存放在數(shù)據(jù)庫(kù)中,本次我們使用List來(lái)進(jìn)行簡(jiǎn)單的模擬,并將其保存在文本文件中,需要時(shí)從文本中讀取,保存時(shí)寫(xiě)入到文件中。

我們使用addFace方法將待注冊(cè)的人臉信息添加到人臉庫(kù)中

public void addFace(String name, AFR_FSDKFace face) {
    try {
      //check if already registered.
      boolean add = true;
      for (FaceRegist frface : mRegister) {
        if (frface.mName.equals(name)) {
          frface.mFaceList.add(face);
          add = false;
          break;
        }
      }
      if (add) { // not registered.
        FaceRegist frface = new FaceRegist(name);
        frface.mFaceList.add(face);
        mRegister.add(frface);
      }

      if (!new File(mDBPath + "/face.txt").exists()) {
        if (!saveInfo()) {
          Log.e(TAG, "save fail!");
        }
      }

      //save name
      FileOutputStream fs = new FileOutputStream(mDBPath + "/face.txt", true);
      ExtOutputStream bos = new ExtOutputStream(fs);
      bos.writeString(name);
      bos.close();
      fs.close();

      //save feature
      fs = new FileOutputStream(mDBPath + "/" + name + ".data", true);
      bos = new ExtOutputStream(fs);
      bos.writeBytes(face.getFeatureData());
      bos.close();
      fs.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

使用loadFaces從文件中讀取人臉

public boolean loadFaces(){
    if (loadInfo()) {
      try {
        for (FaceRegist face : mRegister) {
          Log.d(TAG, "load name:" + face.mName + "'s face feature data.");
          FileInputStream fs = new FileInputStream(mDBPath + "/" + face.mName + ".data");
          ExtInputStream bos = new ExtInputStream(fs);
          AFR_FSDKFace afr = null;
          do {
            if (afr != null) {
              if (mUpgrade) {
                //upgrade data.
              }
              face.mFaceList.add(afr);
            }
            afr = new AFR_FSDKFace();
          } while (bos.readBytes(afr.getFeatureData()));
          bos.close();
          fs.close();
        }
        return true;
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    } else {
      if (!saveInfo()) {
        Log.e(TAG, "save fail!");
      }
    }
    return false;
  }

7.實(shí)現(xiàn)業(yè)務(wù)邏輯

7.1實(shí)現(xiàn)人臉注冊(cè)功能

人臉識(shí)別的前提條件就是人臉信息要先注冊(cè)到人臉庫(kù)中,注冊(cè)人臉庫(kù)

第一步當(dāng)然是獲取待注冊(cè)的照片,我們可以可以使用攝像頭,也可以使用照片。我們使用AlertDialog彈出選擇框

new AlertDialog.Builder(this)
            .setTitle("請(qǐng)選擇注冊(cè)方式")
            .setIcon(android.R.drawable.ic_dialog_info)
            .setItems(new String[]{"打開(kāi)圖片", "拍攝照片"}, this)
            .show();

在對(duì)應(yīng)的事件處理函數(shù)中進(jìn)行處理

switch (which){
  case 1://攝像頭
    Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
    ContentValues values = new ContentValues(1);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    mPath = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    getImageByCamera.putExtra(MediaStore.EXTRA_OUTPUT, mPath);
    startActivityForResult(getImageByCamera, REQUEST_CODE_IMAGE_CAMERA);
    break;
  case 0://圖片
    Intent getImageByalbum = new Intent(Intent.ACTION_GET_CONTENT);
    getImageByalbum.addCategory(Intent.CATEGORY_OPENABLE);
    getImageByalbum.setType("image/jpeg");
    startActivityForResult(getImageByalbum, REQUEST_CODE_IMAGE_OP);
    break;
  default:;
}

獲取一張照片后,后續(xù)我們就需要實(shí)現(xiàn)人臉檢測(cè)功能。

if (requestCode == REQUEST_CODE_IMAGE_OP && resultCode == RESULT_OK) {
      mPath = data.getData();
      String file = getPath(mPath);
      //TODO: add image coversion
    }

在上面的代碼中,我們獲取到了我們需要的圖像數(shù)據(jù)bmp,把圖片取出來(lái)

我們?cè)贏pplication類(lèi)用函數(shù) decodeImage中實(shí)現(xiàn)這段代碼

public static Bitmap decodeImage(String path) {
    Bitmap res;
    try {
      ExifInterface exif = new ExifInterface(path);
      int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

      BitmapFactory.Options op = new BitmapFactory.Options();
      op.inSampleSize = 1;
      op.inJustDecodeBounds = false;
      //op.inMutable = true;
      res = BitmapFactory.decodeFile(path, op);
      //rotate and scale.
      Matrix matrix = new Matrix();

      if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
        matrix.postRotate(90);
      } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
        matrix.postRotate(180);
      } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
        matrix.postRotate(270);
      }

      Bitmap temp = Bitmap.createBitmap(res, 0, 0, res.getWidth(), res.getHeight(), matrix, true);
      Log.d("com.arcsoft", "check target Image:" + temp.getWidth() + "X" + temp.getHeight());

      if (!temp.equals(res)) {
        res.recycle();
      }
      return temp;
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

調(diào)用AFD_FSDK_StillImageFaceDetection返回檢測(cè)到的人臉信息

人臉注冊(cè) ,首先要先檢測(cè)出來(lái)人臉,對(duì)于靜態(tài)圖片,虹軟人臉SDK中對(duì)應(yīng)的是FD,提供了一個(gè)方法名稱(chēng),叫AFD_FSDK_StillImageFaceDetection 。

我們來(lái)看一下參數(shù)列表

android實(shí)現(xiàn)人臉識(shí)別技術(shù)的示例代碼

注意AFD_FSDKFace對(duì)象引擎內(nèi)部重復(fù)使用,如需保存,請(qǐng)clone一份AFD_FSDKFace對(duì)象或另外保存

AFD_FSDKFace是人臉識(shí)別的結(jié)果,定義如下

public class AFD_FSDKFace {
  Rect mRect;
  int mDegree;
  }

mRect定義一個(gè)了一個(gè)矩形框Rect

在此之前我們需要注意虹軟人臉SDK使用的圖像格式是NV21的格式,所以我們需要將獲取到的圖像轉(zhuǎn)化為對(duì)應(yīng)的格式。在Android_extend.jar中提供了對(duì)應(yīng)的轉(zhuǎn)換函數(shù)

byte[] data = new byte[mBitmap.getWidth() * mBitmap.getHeight() * 3 / 2];
        ImageConverter convert = new ImageConverter();
        convert.initial(mBitmap.getWidth(), mBitmap.getHeight(), ImageConverter.CP_PAF_NV21);
        if (convert.convert(mBitmap, data)) {
          Log.d(TAG, "convert ok!");
        }
        convert.destroy();

現(xiàn)在我們就可以調(diào)用AFD_FSDK_StillImageFaceDetection方法了

8.繪出人臉框

在List<AFD_FSDKFace>中保存了檢測(cè)到的人臉的位置信息和深度信息。

我們可以將檢測(cè)到的人臉位置信息在圖片上用一個(gè)矩形框繪制出來(lái)表示檢測(cè)到的人臉信息。

Canvas canvas = mSurfaceHolder.lockCanvas();
  if (canvas != null) {
   Paint mPaint = new Paint();
   boolean fit_horizontal = canvas.getWidth() / (float)src.width() < canvas.getHeight() / (float)src.height() ? true : false;
   float scale = 1.0f;
   if (fit_horizontal) {
     scale = canvas.getWidth() / (float)src.width();
     dst.left = 0;
     dst.top = (canvas.getHeight() - (int)(src.height() * scale)) / 2;
     dst.right = dst.left + canvas.getWidth();
     dst.bottom = dst.top + (int)(src.height() * scale);
   } else {
     scale = canvas.getHeight() / (float)src.height();
     dst.left = (canvas.getWidth() - (int)(src.width() * scale)) / 2;
     dst.top = 0;
     dst.right = dst.left + (int)(src.width() * scale);
     dst.bottom = dst.top + canvas.getHeight();
   }
   canvas.drawBitmap(mBitmap, src, dst, mPaint);
   canvas.save();
   canvas.scale((float) dst.width() / (float) src.width(), (float) dst.height() / (float) src.height());
   canvas.translate(dst.left / scale, dst.top / scale);
   for (AFD_FSDKFace face : result) {
     mPaint.setColor(Color.RED);
     mPaint.setStrokeWidth(10.0f);
     mPaint.setStyle(Paint.Style.STROKE);
     canvas.drawRect(face.getRect(), mPaint);
   }
   canvas.restore();
   mSurfaceHolder.unlockCanvasAndPost(canvas);
   break;
  }
}

9.將人臉注冊(cè)到人臉庫(kù)

檢測(cè)到了人臉,我們可以輸入相應(yīng)的描述信息,加入到人臉庫(kù)中。

為了提高識(shí)別的準(zhǔn)確性,我們可以對(duì)一個(gè)人多次注冊(cè)人臉信息。

public void addFace(String name, AFR_FSDKFace face) {
  try {
   //check if already registered.
   boolean add = true;
   for (FaceRegist frface : mRegister) {
     if (frface.mName.equals(name)) {
      frface.mFaceList.add(face);
      add = false;
      break;
     }
   }
   if (add) { // not registered.
     FaceRegist frface = new FaceRegist(name);
     frface.mFaceList.add(face);
     mRegister.add(frface);
   }

   if (!new File(mDBPath + "/face.txt").exists()) {
     if (!saveInfo()) {
      Log.e(TAG, "save fail!");
     }
   }
   //save name
   FileOutputStream fs = new FileOutputStream(mDBPath + "/face.txt", true);
   ExtOutputStream bos = new ExtOutputStream(fs);
   bos.writeString(name);
   bos.close();
   fs.close();
   //save feature
   fs = new FileOutputStream(mDBPath + "/" + name + ".data", true);
   bos = new ExtOutputStream(fs);
   bos.writeBytes(face.getFeatureData());
   bos.close();
   fs.close();
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
}

最后,別忘記了銷(xiāo)毀人臉檢測(cè)引擎

err = engine.AFD_FSDK_UninitialFaceEngine(); 
Log.d("com.arcsoft", "AFD_FSDK_UninitialFaceEngine =" + err.getCode()); 

10.實(shí)現(xiàn)人臉識(shí)別

上面的代碼準(zhǔn)備完畢后,就可以開(kāi)始我們的人臉識(shí)別的功能了。我們使用一個(gè)第三方的擴(kuò)展庫(kù),ExtGLSurfaceView的擴(kuò)展 庫(kù)CameraGLSurfaceView,用ImageView和TextView顯示檢測(cè)到的人臉和相應(yīng)的描述信息。

首先是定義layout。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

  <com.guo.android_extend.widget.CameraSurfaceView
    android:id="@+id/surfaceView"
    android:layout_width="1dp"
    android:layout_height="1dp"/>

  <com.guo.android_extend.widget.CameraGLSurfaceView
    android:id="@+id/glsurfaceView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"/>

  <ImageView
    android:id="@+id/imageView"
    android:layout_width="120dp"
    android:layout_height="120dp"
    android:layout_marginLeft="10dp"
    android:layout_marginTop="10dp"/>

  <TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/imageView"
    android:layout_alignRight="@+id/imageView"
    android:layout_below="@+id/imageView"
    android:layout_marginTop="10dp"
    android:text="@string/app_name"
    android:textAlignment="center"/>

  <TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/imageView"
    android:layout_alignRight="@+id/imageView"
    android:layout_below="@+id/textView"
    android:layout_marginTop="10dp"
    android:text="@string/app_name"
    android:textAlignment="center"/>
</RelativeLayout>

因?yàn)橐嫘枰膱D像格式是NV21的,所以需要將攝像頭中的圖像格式預(yù)設(shè)置為NV21

public Camera setupCamera() {
  // TODO Auto-generated method stub
  mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
  try {
   Camera.Parameters parameters = mCamera.getParameters();
   parameters.setPreviewSize(mWidth, mHeight);
   parameters.setPreviewFormat(ImageFormat.NV21);

   for( Camera.Size size : parameters.getSupportedPreviewSizes()) {
     Log.d(TAG, "SIZE:" + size.width + "x" + size.height);
   }
   for( Integer format : parameters.getSupportedPreviewFormats()) {
     Log.d(TAG, "FORMAT:" + format);
   }

   List<int[]> fps = parameters.getSupportedPreviewFpsRange();
   for(int[] count : fps) {
     Log.d(TAG, "T:");
     for (int data : count) {
      Log.d(TAG, "V=" + data);
     }
   }
   mCamera.setParameters(parameters);
  } catch (Exception e) {
   e.printStackTrace();
  }
  if (mCamera != null) {
   mWidth = mCamera.getParameters().getPreviewSize().width;
   mHeight = mCamera.getParameters().getPreviewSize().height;
  }
  return mCamera;
}

從攝像頭識(shí)別人臉,需要使用FT庫(kù),F(xiàn)T庫(kù)在人臉跟蹤算法上對(duì)人臉檢測(cè)部分進(jìn)行了優(yōu)化,是專(zhuān)門(mén)為視頻處理而優(yōu)化的庫(kù)。

11.初始化人臉檢測(cè)引擎(FT)

和FD一樣,我們需要初始化人臉識(shí)別FT引擎。

Log.d(TAG, "AFT_FSDK_InitialFaceEngine =" + err.getCode());
err = engine.AFT_FSDK_GetVersion(version);
Log.d(TAG, "AFT_FSDK_GetVersion:" + version.toString() + "," + err.getCode());

在攝像頭的預(yù)覽事件處理函數(shù)中,先調(diào)用FT的人臉識(shí)函數(shù)函數(shù),然后再調(diào)用FR中的人臉信息特征提取數(shù)函數(shù)。

AFT_FSDKError err = engine.AFT_FSDK_FaceFeatureDetect(data, width, height, AFT_FSDKEngine.CP_PAF_NV21, result);

AFR_FSDKError error = engine.AFR_FSDK_ExtractFRFeature(mImageNV21, mWidth, mHeight, AFR_FSDKEngine.CP_PAF_NV21,mAFT_FSDKFace.getRect(), mAFT_FSDKFace.getDegree(), result);

這里面的result中保存了人臉特征信息。我們可以將其保存下來(lái)或下來(lái)并與系統(tǒng)中的其它信息進(jìn)行對(duì)比。

AFR_FSDKMatching score = new AFR_FSDKMatching();
float max = 0.0f;
String name = null;
for (FaceDB.FaceRegist fr : mResgist) {
  for (AFR_FSDKFace face : fr.mFaceList) {
   error = engine.AFR_FSDK_FacePairMatching(result, face, score);
   Log.d(TAG, "Score:" + score.getScore() + ", AFR_FSDK_FacePairMatching=" + error.getCode());
   if (max < score.getScore()) {
     max = score.getScore();
     name = fr.mName;
   }
  }
}

當(dāng)score的特征信息大于0.6時(shí),我們就可以認(rèn)為匹配到了人臉。顯示人臉匹配信息。

上面的循環(huán)中,可以看到,是遍歷了真?zhèn)€庫(kù)進(jìn)行尋找。我們的目的是為了演示,實(shí)際情況下,我們可以在找到一個(gè)匹配值比較高的人臉后,就跳出循環(huán)。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

本文名稱(chēng):android實(shí)現(xiàn)人臉識(shí)別技術(shù)的示例代碼
轉(zhuǎn)載注明:http://bm7419.com/article20/igidjo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、域名注冊(cè)網(wǎng)站改版、商城網(wǎng)站、外貿(mào)建站移動(dòng)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)