環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
.NET 人臉識別庫 ViewFaceCore
這是基於 SeetaFace6 人臉識別開發的 .NET 平台下的人臉識別庫
這是一個使用超簡單的人臉識別庫
這是一個基於 .NET Standard 2.0 開發的庫
這個庫已經發布到 NuGet ,你可以一鍵集成到你的項目
此項目可以免費商業使用
開源協議:Apache-2.0
GitHub地址: ViewFaceCore
十分感謝您的小星星
示例項目地址:WinForm 攝像頭人臉檢測
示例項目效果:
一分鐘在你的項目里集成人臉識別
1. 創建你的 .NET 應用
.NET Standard >= 2.0
.NET Core >= 2.0
.NET Framework >= 4.6.1^2
2. 使用 Nuget 安裝 ViewFaceCore
此 Nuget 包會自動添加依賴的 C++ 庫,以及最精簡的識別模型。
如果需要其它場景的識別模型,請下載 SeetaFace6 模型文件。
3. 在項目中編寫你的代碼
簡單的調用示例
1 static void Main() 2 { 3 ViewFace viewFace = new ViewFace((str) => { Debug.WriteLine(str); }); // 初始化人臉識別類,並設置 日誌回調函數 4 viewFace.DetectorSetting = new DetectorSetting() { FaceSize = 20, MaxWidth = 2000, MaxHeight = 2000, Threshold = 0.5 }; 5 6 // 系統默認使用的輕量級識別模型。如果對精度有要求,請切換到 Normal 模式;並下載需要模型文件 放入生成目錄的 model 文件夾中 7 viewFace.FaceType = FaceType.Normal; 8 // 系統默認使用5個人臉關鍵點。//不建議改動,除非是使用口罩模型。 9 viewFace.MarkType = MarkType.Light; 10 11 #region 識別老照片 12 float[] oldEigenValues; 13 Bitmap oldImg = (Bitmap)Image.FromFile(@"C:\Users\yangw\OneDrive\圖片\Camera Roll\IMG_20181103_142707.jpg"/*老圖片路徑*/); // 從文件中加載照片 // 或者視頻幀等 14 var oldFaces = viewFace.FaceDetector(oldImg); // 檢測圖片中包含的人臉信息。(置信度、位置、大小) 15 if (oldFaces.Length > 0) //識別到人臉 16 { 17 { // 打印人臉信息 18 Console.WriteLine($"識別到的人臉數量:{oldFaces.Length} 。人臉信息:\n"); 19 Console.WriteLine($"序號\t人臉置信度\t位置X\t位置Y\t寬度\t高度"); 20 for (int i = 0; i < oldFaces.Length; i++) 21 { 22 Console.WriteLine($"{i + 1}\t{oldFaces[i].Score}\t{oldFaces[i].Location.X}\t{oldFaces[i].Location.Y}\t{oldFaces[i].Location.Width}\t{oldFaces[i].Location.Height}"); 23 } 24 Console.WriteLine(); 25 } 26 var oldPoints = viewFace.FaceMark(oldImg, oldFaces[0]); // 獲取 第一個人臉 的識別關鍵點。(人臉識別的關鍵點數據) 27 oldEigenValues = viewFace.Extract(oldImg, oldPoints); // 獲取 指定的關鍵點 的特徵值。 28 } 29 else { oldEigenValues = new float[0]; /*未識別到人臉*/ } 30 #endregion 31 32 #region 識別新照片 33 float[] newEigenValues; 34 Bitmap newImg = (Bitmap)Image.FromFile(@"C:\Users\yangw\OneDrive\圖片\Camera Roll\IMG_20181129_224339.jpg"/*新圖片路徑*/); // 從文件中加載照片 // 或者視頻幀等 35 var newFaces = viewFace.FaceDetector(newImg); // 檢測圖片中包含的人臉信息。(置信度、位置、大小) 36 if (newFaces.Length > 0) //識別到人臉 37 { 38 { // 打印人臉信息 39 Console.WriteLine($"識別到的人臉數量:{newFaces.Length} 。人臉信息:\n"); 40 Console.WriteLine($"序號\t人臉置信度\t位置X\t位置Y\t寬度\t高度"); 41 for (int i = 0; i < newFaces.Length; i++) 42 { 43 Console.WriteLine($"{i + 1}\t{newFaces[i].Score}\t{newFaces[i].Location.X}\t{newFaces[i].Location.Y}\t{newFaces[i].Location.Width}\t{newFaces[i].Location.Height}"); 44 } 45 Console.WriteLine(); 46 } 47 var newPoints = viewFace.FaceMark(newImg, newFaces[0]); // 獲取 第一個人臉 的識別關鍵點。(人臉識別的關鍵點數據) 48 newEigenValues = viewFace.Extract(newImg, newPoints); // 獲取 指定的關鍵點 的特徵值。 49 } 50 else { newEigenValues = new float[0]; /*未識別到人臉*/ } 51 #endregion 52 53 try 54 { 55 float similarity = viewFace.Similarity(oldEigenValues, newEigenValues); // 對比兩張照片上的數據,確認是否是同一個人。 56 Console.WriteLine($"閾值 = {Face.Threshold[viewFace.FaceType]}\t相似度 = {similarity}"); 57 Console.WriteLine($"是否是同一個人:{viewFace.IsSelf(similarity)}"); 58 } 59 catch (Exception e) 60 { Console.WriteLine(e); } 61 62 Console.ReadKey(); 63 }
ViewFaceCore 使用示例
三、說明
命名空間:ViewFaceCore.Sharp : 人臉識別類所在的命名空間
| 屬性名稱 | 類型 | 說明 | 默認值 |
| ModelPath | string | 獲取或設置模型路徑 [ 如非必要,請勿修改 ] | ./model/ |
| FaceType | FaceType | 獲取或設置人臉類型 | FaceType.Light |
| MarkType | MarkType | 獲取或設置人臉關鍵點類型 | MarkType.Light |
| DetectorSetting | DetectorSetting | 獲取或設置人臉檢測器設置 | new DetectorSetting() |
1 using System.Drawing; 2 using ViewFaceCore.Sharp; 3 using ViewFaceCore.Sharp.Model; 4 5 // 識別 bitmap 中的人臉,並返回人臉的信息。 6 FaceInfo[] FaceDetector(Bitmap); 7 8 // 識別 bitmap 中指定的人臉信息 info 的關鍵點坐標。 9 FaceMarkPoint[] FaceMark(Bitmap, FaceInfo); 10 11 // 提取人臉特徵值。 12 float[] Extract(Bitmap, FaceMarkPoint[]); 13 14 // 計算特徵值相似度。 15 float Similarity(float[], float[]); 16 17 // 判斷相似度是否為同一個人。 18 bool IsSelf(float);
四、實現
此項目受到了 SeetaFaceEngine.NET 項目的啟發
這個項目本質上來說還是調用了 SeetaFace 的 C++ 類庫來實現的人臉識別功能。針對本人遇到過的相關的類庫的使用都不太方便,而且使用的 SeetaFace 的版本較老,故萌生了自己重新開發的想法。
本項目在開發完成之後為了方便調用,採用了 Nuget 包的形式,將所有需要的依賴以及最小識別模型一起打包。在使用時非常簡單,只需要 nuget 安裝,編寫代碼,運行即可,不需要多餘的操作。
首先查看 SeetaFace ,已經更新到了v3(v6即v3)(上面前輩的項目是基於v1開發的),最新版本暫時沒有開源,但是可以免費商用。然後是根據以前的經驗和 SeetaFace6 文檔的指導,以及前輩的項目,做了以下操作。
1.對SeetaFace6 的接口進行了 C++ 形式的封裝。
目前主要實現了 人臉檢測,關鍵點提取,特徵值提取,特徵值對比幾個人臉識別中的基礎接口。有了這幾個接口,可以完整的實現一套人臉識別和驗證的流程。
1 #include "seeta/FaceDetector.h" 2 #include "seeta/FaceLandmarker.h" 3 #include "seeta/FaceRecognizer.h" 4 5 #include <time.h> 6 7 #define View_Api extern "C" __declspec(dllexport) 8 9 using namespace std; 10 11 typedef void(_stdcall* LogCallBack)(const char* logText); 12 13 string modelPath = "./model/"; // 模型所在路徑 14 LogCallBack logger = NULL; // 日誌回調函數 15 16 // 打印日誌 17 void WriteLog(string str) { if (logger != NULL) { logger(str.c_str()); } } 18 19 void WriteMessage(string fanctionName, string message) { WriteLog(fanctionName + "\t Message:" + message); } 20 void WriteModelName(string fanctionName, string modelName) { WriteLog(fanctionName + "\t Model.Name:" + modelName); } 21 void WriteRunTime(string fanctionName, int start) { WriteLog(fanctionName + "\t Run.Time:" + to_string(clock() - start) + " ms"); } 22 void WriteError(string fanctionName, const std::exception& e) { WriteLog(fanctionName + "\t Error:" + e.what()); } 23 24 // 註冊日誌回調函數 25 View_Api void V_SetLogFunction(LogCallBack writeLog) 26 { 27 logger = writeLog; 28 WriteMessage(__FUNCDNAME__, "Successed."); 29 } 30 31 // 設置人臉模型目錄 32 View_Api void V_SetModelPath(const char* path) 33 { 34 modelPath = path; 35 WriteMessage(__FUNCDNAME__, "Model.Path:" + modelPath); 36 } 37 // 獲取人臉模型目錄 38 View_Api bool V_GetModelPath(char** path) 39 { 40 try 41 { 42 #pragma warning(disable:4996) 43 strcpy(*path, modelPath.c_str()); 44 45 return true; 46 } 47 catch (const std::exception& e) 48 { 49 WriteError(__FUNCDNAME__, e); 50 return false; 51 } 52 } 53 54 seeta::FaceDetector* v_faceDetector = NULL; 55 56 // 人臉檢測結果 57 static SeetaFaceInfoArray detectorInfos; 58 // 人臉數量檢測器 59 View_Api int V_DetectorSize(unsigned char* imgData, int width, int height, int channels, double faceSize = 20, double threshold = 0.9, double maxWidth = 2000, double maxHeight = 2000, int type = 0) 60 { 61 try { 62 clock_t start = clock(); 63 64 SeetaImageData img = { width, height, channels, imgData }; 65 if (v_faceDetector == NULL) { 66 seeta::ModelSetting setting; 67 setting.set_device(SEETA_DEVICE_CPU); 68 string modelName = "face_detector.csta"; 69 switch (type) 70 { 71 case 1: modelName = "mask_detector.csta"; break; 72 } 73 setting.append(modelPath + modelName); 74 WriteModelName(__FUNCDNAME__, modelName); 75 v_faceDetector = new seeta::FaceDetector(setting); 76 } 77 78 if (faceSize != 20) { v_faceDetector->set(seeta::FaceDetector::Property::PROPERTY_MIN_FACE_SIZE, faceSize); } 79 if (threshold != 0.9) { v_faceDetector->set(seeta::FaceDetector::Property::PROPERTY_THRESHOLD, threshold); } 80 if (maxWidth != 2000) { v_faceDetector->set(seeta::FaceDetector::Property::PROPERTY_MAX_IMAGE_WIDTH, maxWidth); } 81 if (maxHeight != 2000) { v_faceDetector->set(seeta::FaceDetector::Property::PROPERTY_MAX_IMAGE_HEIGHT, maxHeight); } 82 83 auto infos = v_faceDetector->detect(img); 84 detectorInfos = infos; 85 86 WriteRunTime("V_Detector", start); // 此方法已經是人臉檢測的全過程,故計時器显示為 人臉識別方法 87 return infos.size; 88 } 89 catch (const std::exception& e) 90 { 91 WriteError(__FUNCDNAME__, e); 92 return -1; 93 } 94 } 95 // 人臉檢測器 96 View_Api bool V_Detector(float* score, int* x, int* y, int* width, int* height) 97 { 98 try 99 { 100 //clock_t start = clock(); 101 102 for (int i = 0; i < detectorInfos.size; i++, detectorInfos.data++) 103 { 104 *score = detectorInfos.data->score; 105 *x = detectorInfos.data->pos.x; 106 *y = detectorInfos.data->pos.y; 107 *width = detectorInfos.data->pos.width; 108 *height = detectorInfos.data->pos.height; 109 score++, x++, y++, width++, height++; 110 } 111 detectorInfos.data = NULL; 112 detectorInfos.size = NULL; 113 114 //WriteRunTime(__FUNCDNAME__, start); // 此方法只是將 人臉數量檢測器 獲取到的數據賦值傳遞,並不耗時。故不显示此方法的調用時間 115 return true; 116 } 117 catch (const std::exception& e) 118 { 119 WriteError(__FUNCDNAME__, e); 120 return false; 121 } 122 } 123 124 125 seeta::FaceLandmarker* v_faceLandmarker = NULL; 126 // 人臉關鍵點數量 127 View_Api int V_FaceMarkSize(int type = 0) 128 { 129 try 130 { 131 clock_t start = clock(); 132 133 if (v_faceLandmarker == NULL) { 134 seeta::ModelSetting setting; 135 setting.set_device(SEETA_DEVICE_CPU); 136 string modelName = "face_landmarker_pts68.csta"; 137 switch (type) 138 { 139 case 1: modelName = "face_landmarker_mask_pts5.csta"; break; 140 case 2: modelName = "face_landmarker_pts5.csta"; break; 141 } 142 setting.append(modelPath + modelName); 143 WriteModelName(__FUNCDNAME__, modelName); 144 v_faceLandmarker = new seeta::FaceLandmarker(setting); 145 } 146 int size = v_faceLandmarker->number(); 147 148 WriteRunTime(__FUNCDNAME__, start); 149 return size; 150 } 151 catch (const std::exception& e) 152 { 153 WriteError(__FUNCDNAME__, e); 154 return -1; 155 } 156 } 157 // 人臉關鍵點 158 View_Api bool V_FaceMark(unsigned char* imgData, int width, int height, int channels, int x, int y, int fWidth, int fHeight, double* pointX, double* pointY, int type = 0) 159 { 160 try 161 { 162 clock_t start = clock(); 163 164 SeetaImageData img = { width, height, channels, imgData }; 165 SeetaRect face = { x, y, fWidth, fHeight }; 166 if (v_faceLandmarker == NULL) { 167 seeta::ModelSetting setting; 168 setting.set_device(SEETA_DEVICE_CPU); 169 string modelName = "face_landmarker_pts68.csta"; 170 switch (type) 171 { 172 case 1: modelName = "face_landmarker_mask_pts5.csta"; break; 173 case 2: modelName = "face_landmarker_pts5.csta"; break; 174 } 175 setting.append(modelPath + modelName); 176 WriteModelName(__FUNCDNAME__, modelName); 177 v_faceLandmarker = new seeta::FaceLandmarker(setting); 178 } 179 std::vector<SeetaPointF> _points = v_faceLandmarker->mark(img, face); 180 181 if (!_points.empty()) { 182 for (auto iter = _points.begin(); iter != _points.end(); iter++) 183 { 184 *pointX = (*iter).x; 185 *pointY = (*iter).y; 186 pointX++; 187 pointY++; 188 } 189 190 WriteRunTime(__FUNCDNAME__, start); 191 return true; 192 } 193 else { return false; } 194 } 195 catch (const std::exception& e) 196 { 197 WriteError(__FUNCDNAME__, e); 198 return false; 199 } 200 } 201 202 seeta::FaceRecognizer* v_faceRecognizer = NULL; 203 // 獲取人臉特徵值長度 204 View_Api int V_ExtractSize(int type = 0) 205 { 206 try 207 { 208 clock_t start = clock(); 209 210 if (v_faceRecognizer == NULL) { 211 seeta::ModelSetting setting; 212 setting.set_id(0); 213 setting.set_device(SEETA_DEVICE_CPU); 214 string modelName = "face_recognizer.csta"; 215 switch (type) 216 { 217 case 1: modelName = "face_recognizer_mask.csta"; break; 218 case 2: modelName = "face_recognizer_light.csta"; break; 219 } 220 setting.append(modelPath + modelName); 221 WriteModelName(__FUNCDNAME__, modelName); 222 v_faceRecognizer = new seeta::FaceRecognizer(setting); 223 } 224 int length = v_faceRecognizer->GetExtractFeatureSize(); 225 226 WriteRunTime(__FUNCDNAME__, start); 227 return length; 228 } 229 catch (const std::exception& e) 230 { 231 WriteError(__FUNCDNAME__, e); 232 return -1; 233 } 234 } 235 // 提取人臉特徵值 236 View_Api bool V_Extract(unsigned char* imgData, int width, int height, int channels, SeetaPointF* points, float* features, int type = 0) 237 { 238 try 239 { 240 clock_t start = clock(); 241 242 SeetaImageData img = { width, height, channels, imgData }; 243 if (v_faceRecognizer == NULL) { 244 seeta::ModelSetting setting; 245 setting.set_id(0); 246 setting.set_device(SEETA_DEVICE_CPU); 247 string modelName = "face_recognizer.csta"; 248 switch (type) 249 { 250 case 1: modelName = "face_recognizer_mask.csta"; break; 251 case 2: modelName = "face_recognizer_light.csta"; break; 252 } 253 setting.append(modelPath + modelName); 254 WriteModelName(__FUNCDNAME__, modelName); 255 v_faceRecognizer = new seeta::FaceRecognizer(setting); 256 } 257 int length = v_faceRecognizer->GetExtractFeatureSize(); 258 std::shared_ptr<float> _features(new float[v_faceRecognizer->GetExtractFeatureSize()], std::default_delete<float[]>()); 259 v_faceRecognizer->Extract(img, points, _features.get()); 260 261 for (int i = 0; i < length; i++) 262 { 263 *features = _features.get()[i]; 264 features++; 265 } 266 267 WriteRunTime(__FUNCDNAME__, start); 268 return true; 269 270 } 271 catch (const std::exception& e) 272 { 273 WriteError(__FUNCDNAME__, e); 274 return false; 275 } 276 } 277 // 人臉特徵值相似度計算 278 View_Api float V_CalculateSimilarity(float* leftFeatures, float* rightFeatures, int type = 0) 279 { 280 try 281 { 282 clock_t start = clock(); 283 284 if (v_faceRecognizer == NULL) { 285 seeta::ModelSetting setting; 286 setting.set_id(0); 287 setting.set_device(SEETA_DEVICE_CPU); 288 string modelName = "face_recognizer.csta"; 289 switch (type) 290 { 291 case 1: modelName = "face_recognizer_mask.csta"; break; 292 case 2: modelName = "face_recognizer_light.csta"; break; 293 } 294 setting.append(modelPath + modelName); 295 WriteModelName(__FUNCDNAME__, modelName); 296 v_faceRecognizer = new seeta::FaceRecognizer(setting); 297 } 298 299 auto similarity = v_faceRecognizer->CalculateSimilarity(leftFeatures, rightFeatures); 300 WriteMessage(__FUNCDNAME__, "Similarity = " + to_string(similarity)); 301 WriteRunTime(__FUNCDNAME__, start); 302 return similarity; 303 } 304 catch (const std::exception& e) 305 { 306 WriteError(__FUNCDNAME__, e); 307 return -1; 308 } 309 } 310 311 // 釋放資源 312 View_Api void V_Dispose() 313 { 314 if (v_faceDetector != NULL) delete v_faceDetector; 315 if (v_faceLandmarker != NULL) delete v_faceLandmarker; 316 if (v_faceRecognizer != NULL) delete v_faceRecognizer; 317 }
C++ 封裝層
2.採用 C# 對上訴接口進行了導入。
因為C++的項目測CPU架構區分x86和x64,所以C# 層也需要區分架構封裝
using System.Runtime.InteropServices; using System.Text; using ViewFaceCore.Sharp.Model; namespace ViewFaceCore.Plus { /// <summary> /// 日誌回調函數 /// </summary> /// <param name="logText"></param> public delegate void LogCallBack(string logText); class ViewFacePlus64 { const string LibraryPath = @"FaceLibraries\x64\ViewFace.dll"; /// <summary> /// 設置日誌回調函數(用於日誌打印) /// </summary> /// <param name="writeLog"></param> [DllImport(LibraryPath, EntryPoint = "V_SetLogFunction", CallingConvention = CallingConvention.Cdecl)] public static extern void SetLogFunction(LogCallBack writeLog); /// <summary> /// 設置人臉模型的目錄 /// </summary> /// <param name="path"></param> [DllImport(LibraryPath, EntryPoint = "V_SetModelPath", CallingConvention = CallingConvention.Cdecl)] private extern static void SetModelPath(byte[] path); /// <summary> /// 設置人臉模型的目錄 /// </summary> /// <param name="path"></param> public static void SetModelPath(string path) => SetModelPath(Encoding.UTF8.GetBytes(path)); /// <summary> /// 釋放使用的資源 /// </summary> [DllImport(LibraryPath, EntryPoint = "V_Dispose", CallingConvention = CallingConvention.Cdecl)] public extern static void ViewDispose(); /// <summary> /// 獲取人臉模型的目錄 /// </summary> /// <param name="path"></param> [DllImport(LibraryPath, EntryPoint = "V_GetModelPath", CallingConvention = CallingConvention.Cdecl)] private extern static bool GetModelPathEx(ref string path); /// <summary> /// 獲取人臉模型的目錄 /// </summary> public static string GetModelPath() { string path = string.Empty; GetModelPathEx(ref path); return path; } /// <summary> /// 人臉檢測器檢測到的人臉數量 /// </summary> /// <param name="imgData"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="channels"></param> /// <param name="faceSize">最小人臉是人臉檢測器常用的一個概念,默認值為20,單位像素。 /// <para>最小人臉和檢測器性能息息相關。主要方面是速度,使用建議上,我們建議在應用範圍內,這個值設定的越大越好。SeetaFace採用的是BindingBox Regresion的方式訓練的檢測器。如果最小人臉參數設置為80的話,從檢測能力上,可以將原圖縮小的原來的1/4,這樣從計算複雜度上,能夠比最小人臉設置為20時,提速到16倍。</para> /// </param> /// <param name="threshold">檢測器閾值默認值是0.9,合理範圍為[0, 1]。這個值一般不進行調整,除了用來處理一些極端情況。這個值設置的越小,漏檢的概率越小,同時誤檢的概率會提高</param> /// <param name="maxWidth">可檢測的圖像最大寬度。默認值2000。</param> /// <param name="maxHeight">可檢測的圖像最大高度。默認值2000。</param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_DetectorSize", CallingConvention = CallingConvention.Cdecl)] public extern static int DetectorSize(byte[] imgData, int width, int height, int channels, double faceSize = 20, double threshold = 0.9, double maxWidth = 2000, double maxHeight = 2000, int type = 0); /// <summary> /// 人臉檢測器 /// <para>調用此方法前必須先調用 <see cref="DetectorSize(byte[], int, int, int, double, double, double, double, int)"/></para> /// </summary> /// <param name="score">人臉置信度集合</param> /// <param name="x">人臉位置集合</param> /// <param name="y">人臉位置集合</param> /// <param name="width">人臉大小集合</param> /// <param name="height">人臉大小集合</param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_Detector", CallingConvention = CallingConvention.Cdecl)] public extern static bool Detector(float[] score, int[] x, int[] y, int[] width, int[] height); /// <summary> /// 人臉關鍵點數量 /// </summary> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_FaceMarkSize", CallingConvention = CallingConvention.Cdecl)] public extern static int FaceMarkSize(int type = 0); /// <summary> /// 人臉關鍵點 /// </summary> /// <param name="imgData"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="channels"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="fWidth"></param> /// <param name="fHeight"></param> /// <param name="pointX"></param> /// <param name="pointY"></param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_FaceMark", CallingConvention = CallingConvention.Cdecl)] public extern static bool FaceMark(byte[] imgData, int width, int height, int channels, int x, int y, int fWidth, int fHeight, double[] pointX, double[] pointY, int type = 0); /// <summary> /// 提取特徵值 /// </summary> /// <param name="imgData"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="channels"></param> /// <param name="points"></param> /// <param name="features"></param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_Extract", CallingConvention = CallingConvention.Cdecl)] public extern static bool Extract(byte[] imgData, int width, int height, int channels, FaceMarkPoint[] points, float[] features, int type = 0); /// <summary> /// 特徵值大小 /// </summary> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_ExtractSize", CallingConvention = CallingConvention.Cdecl)] public extern static int ExtractSize(int type = 0); /// <summary> /// 計算相似度 /// </summary> /// <param name="leftFeatures"></param> /// <param name="rightFeatures"></param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_CalculateSimilarity", CallingConvention = CallingConvention.Cdecl)] public extern static float Similarity(float[] leftFeatures, float[] rightFeatures, int type = 0); } class ViewFacePlus32 { const string LibraryPath = @"FaceLibraries\x86\ViewFace.dll"; /// <summary> /// 設置日誌回調函數(用於日誌打印) /// </summary> /// <param name="writeLog"></param> [DllImport(LibraryPath, EntryPoint = "V_SetLogFunction", CallingConvention = CallingConvention.Cdecl)] public static extern void SetLogFunction(LogCallBack writeLog); /// <summary> /// 設置人臉模型的目錄 /// </summary> /// <param name="path"></param> [DllImport(LibraryPath, EntryPoint = "V_SetModelPath", CallingConvention = CallingConvention.Cdecl)] private extern static void SetModelPath(byte[] path); /// <summary> /// 設置人臉模型的目錄 /// </summary> /// <param name="path"></param> public static void SetModelPath(string path) => SetModelPath(Encoding.UTF8.GetBytes(path)); /// <summary> /// 釋放使用的資源 /// </summary> [DllImport(LibraryPath, EntryPoint = "V_Dispose", CallingConvention = CallingConvention.Cdecl)] public extern static void ViewDispose(); /// <summary> /// 獲取人臉模型的目錄 /// </summary> /// <param name="path"></param> [DllImport(LibraryPath, EntryPoint = "V_GetModelPath", CallingConvention = CallingConvention.Cdecl)] private extern static bool GetModelPathEx(ref string path); /// <summary> /// 獲取人臉模型的目錄 /// </summary> public static string GetModelPath() { string path = string.Empty; GetModelPathEx(ref path); return path; } /// <summary> /// 人臉檢測器檢測到的人臉數量 /// </summary> /// <param name="imgData"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="channels"></param> /// <param name="faceSize">最小人臉是人臉檢測器常用的一個概念,默認值為20,單位像素。 /// <para>最小人臉和檢測器性能息息相關。主要方面是速度,使用建議上,我們建議在應用範圍內,這個值設定的越大越好。SeetaFace採用的是BindingBox Regresion的方式訓練的檢測器。如果最小人臉參數設置為80的話,從檢測能力上,可以將原圖縮小的原來的1/4,這樣從計算複雜度上,能夠比最小人臉設置為20時,提速到16倍。</para> /// </param> /// <param name="threshold">檢測器閾值默認值是0.9,合理範圍為[0, 1]。這個值一般不進行調整,除了用來處理一些極端情況。這個值設置的越小,漏檢的概率越小,同時誤檢的概率會提高</param> /// <param name="maxWidth">可檢測的圖像最大寬度。默認值2000。</param> /// <param name="maxHeight">可檢測的圖像最大高度。默認值2000。</param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_DetectorSize", CallingConvention = CallingConvention.Cdecl)] public extern static int DetectorSize(byte[] imgData, int width, int height, int channels, double faceSize = 20, double threshold = 0.9, double maxWidth = 2000, double maxHeight = 2000, int type = 0); /// <summary> /// 人臉檢測器 /// <para>調用此方法前必須先調用 <see cref="DetectorSize(byte[], int, int, int, double, double, double, double, int)"/></para> /// </summary> /// <param name="score">人臉置信度集合</param> /// <param name="x">人臉位置集合</param> /// <param name="y">人臉位置集合</param> /// <param name="width">人臉大小集合</param> /// <param name="height">人臉大小集合</param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_Detector", CallingConvention = CallingConvention.Cdecl)] public extern static bool Detector(float[] score, int[] x, int[] y, int[] width, int[] height); /// <summary> /// 人臉關鍵點數量 /// </summary> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_FaceMarkSize", CallingConvention = CallingConvention.Cdecl)] public extern static int FaceMarkSize(int type = 0); /// <summary> /// 人臉關鍵點 /// </summary> /// <param name="imgData"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="channels"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="fWidth"></param> /// <param name="fHeight"></param> /// <param name="pointX"></param> /// <param name="pointY"></param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_FaceMark", CallingConvention = CallingConvention.Cdecl)] public extern static bool FaceMark(byte[] imgData, int width, int height, int channels, int x, int y, int fWidth, int fHeight, double[] pointX, double[] pointY, int type = 0); /// <summary> /// 提取特徵值 /// </summary> /// <param name="imgData"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="channels"></param> /// <param name="points"></param> /// <param name="features"></param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_Extract", CallingConvention = CallingConvention.Cdecl)] public extern static bool Extract(byte[] imgData, int width, int height, int channels, FaceMarkPoint[] points, float[] features, int type = 0); /// <summary> /// 特徵值大小 /// </summary> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_ExtractSize", CallingConvention = CallingConvention.Cdecl)] public extern static int ExtractSize(int type = 0); /// <summary> /// 計算相似度 /// </summary> /// <param name="leftFeatures"></param> /// <param name="rightFeatures"></param> /// <param name="type"></param> /// <returns></returns> [DllImport(LibraryPath, EntryPoint = "V_CalculateSimilarity", CallingConvention = CallingConvention.Cdecl)] public extern static float Similarity(float[] leftFeatures, float[] rightFeatures, int type = 0); } }
C# 導入層
3.採用 C# 的面向對象的封裝
因為C#的項目默認都是 AnyCPU,所以為了簡化調用,在這一層封裝的時候增加了架構判斷,當在你的項目中引用的時候,不用做任何修改。
且因為C++的C#導入方法在和原生的C#寫法略有差異,且數據的轉換和傳遞比較麻煩,所以類庫中對外隱藏了 C# 導入層。並使用大家都更熟悉的C#的面向對象的方式進行進一步的封裝和簡化。
1 /// <summary> 2 /// 人臉識別類 3 /// </summary> 4 public class ViewFace 5 { 6 bool Platform64 { get; set; } = false; 7 // <para>需要模型:<see langword=""/></para> 8 9 // ctor 10 /// <summary> 11 /// 使用默認的模型目錄初始化人臉識別類 12 /// </summary> 13 public ViewFace() : this("./model/") { } 14 /// <summary> 15 /// 使用指定的模型目錄初始化人臉識別類 16 /// </summary> 17 /// <param name="modelPath">模型目錄</param> 18 public ViewFace(string modelPath) 19 { 20 Platform64 = IntPtr.Size == 8; 21 if (Platform64) 22 { ViewFacePlus64.SetModelPath(modelPath); } 23 else 24 { ViewFacePlus32.SetModelPath(modelPath); } 25 } 26 /// <summary> 27 /// 使用指定的日誌回調函數初始化人臉識別類 28 /// </summary> 29 /// <param name="action">日誌回調函數</param> 30 public ViewFace(LogCallBack action) : this("./model/", action) { } 31 /// <summary> 32 /// 使用指定的模型目錄、日誌回調函數初始化人臉識別類 33 /// </summary> 34 /// <param name="modelPath">模型目錄</param> 35 /// <param name="action">日誌回調函數</param> 36 public ViewFace(string modelPath, LogCallBack action) : this(modelPath) 37 { 38 if (Platform64) 39 { ViewFacePlus64.SetLogFunction(action); } 40 else 41 { ViewFacePlus32.SetLogFunction(action); } 42 } 43 44 // public property 45 /// <summary> 46 /// 獲取或設置模型路徑 47 /// </summary> 48 public string ModelPath 49 { 50 get 51 { 52 if (Platform64) 53 { return ViewFacePlus64.GetModelPath(); } 54 else 55 { return ViewFacePlus32.GetModelPath(); } 56 } 57 set 58 { 59 if (Platform64) 60 { ViewFacePlus64.SetModelPath(value); } 61 else 62 { ViewFacePlus32.SetModelPath(value); } 63 } 64 } 65 /// <summary> 66 /// 獲取或設置人臉類型 67 /// <para> 68 /// <listheader>此屬性可影響到以下方法:</listheader><br /> 69 /// • <c><see cref="FaceDetector(Bitmap)"/></c><br /> 70 /// • <c><see cref="Extract(Bitmap, FaceMarkPoint[])"/></c><br /> 71 /// • <c><see cref="Similarity(float[], float[])"/></c><br /> 72 /// </para> 73 /// </summary> 74 public FaceType FaceType { get; set; } = FaceType.Light; 75 /// <summary> 76 /// 獲取或設置人臉關鍵點類型 77 /// <para> 78 /// <listheader>此屬性可影響到以下方法:</listheader><br /> 79 /// • <c><see cref="FaceMark(Bitmap, FaceInfo)"/></c><br /> 80 /// </para> 81 /// </summary> 82 public MarkType MarkType { get; set; } = MarkType.Light; 83 /// <summary> 84 /// 獲取或設置人臉檢測器設置 85 /// </summary> 86 public DetectorSetting DetectorSetting { get; set; } = new DetectorSetting(); 87 88 89 // public method 90 /// <summary> 91 /// 識別 <paramref name="bitmap"/> 中的人臉,並返回人臉的信息。 92 /// <para> 93 /// 當 <c><see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Normal"/> <see langword="||"/> <see cref="FaceType.Light"/></c> 時, 需要模型:<see langword="face_detector.csta"/><br/> 94 /// 當 <c><see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Mask"/></c> 時, 需要模型:<see langword="mask_detector.csta"/><br/> 95 /// </para> 96 /// </summary> 97 /// <param name="bitmap">包含人臉的圖片</param> 98 /// <returns></returns> 99 public FaceInfo[] FaceDetector(Bitmap bitmap) 100 { 101 byte[] bgr = ImageSet.Get24BGRFromBitmap(bitmap, out int width, out int height, out int channels); 102 int size; 103 if (Platform64) 104 { size = ViewFacePlus64.DetectorSize(bgr, width, height, channels, DetectorSetting.FaceSize, DetectorSetting.Threshold, DetectorSetting.MaxWidth, DetectorSetting.MaxHeight, (int)FaceType); } 105 else 106 { size = ViewFacePlus32.DetectorSize(bgr, width, height, channels, DetectorSetting.FaceSize, DetectorSetting.Threshold, DetectorSetting.MaxWidth, DetectorSetting.MaxHeight, (int)FaceType); } 107 float[] _socre = new float[size]; 108 int[] _x = new int[size]; 109 int[] _y = new int[size]; 110 int[] _width = new int[size]; 111 int[] _height = new int[size]; 112 if (Platform64) 113 { _ = ViewFacePlus64.Detector(_socre, _x, _y, _width, _height); } 114 else 115 { _ = ViewFacePlus32.Detector(_socre, _x, _y, _width, _height); } 116 List<FaceInfo> infos = new List<FaceInfo>(); 117 for (int i = 0; i < size; i++) 118 { 119 infos.Add(new FaceInfo() { Score = _socre[i], Location = new FaceRect() { X = _x[i], Y = _y[i], Width = _width[i], Height = _height[i] } }); 120 } 121 return infos.ToArray(); 122 } 123 124 /// <summary> 125 /// 識別 <paramref name="bitmap"/> 中指定的人臉信息 <paramref name="info"/> 的關鍵點坐標。 126 /// <para> 127 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Normal"/> 時, 需要模型:<see langword="face_landmarker_pts68.csta"/><br/> 128 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Mask"/> 時, 需要模型:<see langword="face_landmarker_mask_pts5.csta"/><br/> 129 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Light"/> 時, 需要模型:<see langword="face_landmarker_pts5.csta"/><br/> 130 /// </para> 131 /// </summary> 132 /// <param name="bitmap">包含人臉的圖片</param> 133 /// <param name="info">指定的人臉信息</param> 134 /// <returns></returns> 135 public FaceMarkPoint[] FaceMark(Bitmap bitmap, FaceInfo info) 136 { 137 byte[] bgr = ImageSet.Get24BGRFromBitmap(bitmap, out int width, out int height, out int channels); 138 int size; 139 if (Platform64) 140 { size = ViewFacePlus64.FaceMarkSize((int)MarkType); } 141 else 142 { size = ViewFacePlus32.FaceMarkSize((int)MarkType); } 143 double[] _pointX = new double[size]; 144 double[] _pointY = new double[size]; 145 bool val; 146 if (Platform64) 147 { val = ViewFacePlus64.FaceMark(bgr, width, height, channels, info.Location.X, info.Location.Y, info.Location.Width, info.Location.Height, _pointX, _pointY, (int)MarkType); } 148 else 149 { val = ViewFacePlus32.FaceMark(bgr, width, height, channels, info.Location.X, info.Location.Y, info.Location.Width, info.Location.Height, _pointX, _pointY, (int)MarkType); } 150 if (val) 151 { 152 List<FaceMarkPoint> points = new List<FaceMarkPoint>(); 153 for (int i = 0; i < size; i++) 154 { points.Add(new FaceMarkPoint() { X = _pointX[i], Y = _pointY[i] }); } 155 return points.ToArray(); 156 } 157 else 158 { throw new Exception("人臉關鍵點獲取失敗"); } 159 } 160 161 /// <summary> 162 /// 提取人臉特徵值。 163 /// <para> 164 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Normal"/> 時, 需要模型:<see langword="face_recognizer.csta"/><br/> 165 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Mask"/> 時, 需要模型:<see langword="face_recognizer_mask.csta"/><br/> 166 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Light"/> 時, 需要模型:<see langword="face_recognizer_light.csta"/><br/> 167 /// </para> 168 /// </summary> 169 /// <param name="bitmap"></param> 170 /// <param name="points"></param> 171 /// <returns></returns> 172 public float[] Extract(Bitmap bitmap, FaceMarkPoint[] points) 173 { 174 byte[] bgr = ImageSet.Get24BGRFromBitmap(bitmap, out int width, out int height, out int channels); 175 float[] features; 176 if (Platform64) 177 { features = new float[ViewFacePlus64.ExtractSize((int)FaceType)]; } 178 else 179 { features = new float[ViewFacePlus32.ExtractSize((int)FaceType)]; } 180 181 if (Platform64) 182 { ViewFacePlus64.Extract(bgr, width, height, channels, points, features, (int)FaceType); } 183 else 184 { ViewFacePlus32.Extract(bgr, width, height, channels, points, features, (int)FaceType); } 185 return features; 186 } 187 188 /// <summary> 189 /// 計算特徵值相似度。 190 /// <para>只能計算相同 <see cref="FaceType"/> 計算出的特徵值</para> 191 /// <para> 192 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Normal"/> 時, 需要模型:<see langword="face_recognizer.csta"/><br/> 193 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Mask"/> 時, 需要模型:<see langword="face_recognizer_mask.csta"/><br/> 194 /// 當 <see cref="FaceType"/> <see langword="="/> <see cref="FaceType.Light"/> 時, 需要模型:<see langword="face_recognizer_light.csta"/><br/> 195 /// </para> 196 /// </summary> 197 /// <exception cref="ArgumentException"/> 198 /// <exception cref="ArgumentNullException"/> 199 /// <param name="leftFeatures"></param> 200 /// <param name="rightFeatures"></param> 201 /// <returns></returns> 202 public float Similarity(float[] leftFeatures, float[] rightFeatures) 203 { 204 if (leftFeatures.Length == 0 || rightFeatures.Length == 0) 205 throw new ArgumentNullException("參數不能為空", nameof(leftFeatures)); 206 if (leftFeatures.Length != rightFeatures.Length) 207 throw new ArgumentException("兩個參數長度不一致"); 208 209 210 if (Platform64) 211 { return ViewFacePlus64.Similarity(leftFeatures, rightFeatures, (int)FaceType); } 212 else 213 { return ViewFacePlus32.Similarity(leftFeatures, rightFeatures, (int)FaceType); } 214 } 215 216 /// <summary> 217 /// 判斷相似度是否為同一個人。 218 /// </summary> 219 /// <param name="similarity">相似度</param> 220 /// <returns></returns> 221 public bool IsSelf(float similarity) => similarity > Face.Threshold[FaceType]; 222 223 /// <summary> 224 /// 釋放資源 225 /// </summary> 226 ~ViewFace() 227 { 228 if (Platform64) 229 { ViewFacePlus64.ViewDispose(); } 230 else 231 { ViewFacePlus32.ViewDispose(); } 232 } 233 }
C# 面向對象層
五、也許…
想起 GitHub 密碼,持續更新…
刪除代碼倉庫跑路…
在 GitHub 報告Bug…
向我 發送郵件
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
特斯拉當家電動車 Model S 不再完美無缺,去年給予 Model S 最高評級的消費者評鑒雜誌《Consumer Reports》點出 Model S 仍許多有小缺陷待改進。 《Consumer Reports》指出,Model S 多在跑超過一萬哩後出現問題,例如里程數超過 1.2 萬哩後,中央控制螢幕在會有反白的狀況,使多項功能無法操作。此外,還有車頂會發出異常噪音,前置行李箱蓋會自動開啟等問題。 Model S 去年 5 月在《Consumer Reports》評鑑中拿下 99 分(滿分 100 分),創史上最高分,之後並在 11 月獲選為年度 10 大好車第一名。 對此,特斯拉執行長 Elon Musk 7 月 31 日曾坦承,較早一批出廠的 Model S 的確有些生產上的瑕疵,但目前出廠的新車多已作修正。 (圖片來源:)
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
是將系統訪問限製為授權用戶的一種方法,是圍繞角色和特權定義的與策略無關的訪問控制機制,RBAC的組件使執行用戶分配變得很簡單。
在組織內部,將為各種職務創建角色。執行某些操作的權限已分配給特定角色。成員或職員(或其他系統用戶)被分配了特定角色,並且通過這些角色分配獲得執行特定系統功能所需的權限。由於未直接為用戶分配權限,而是僅通過其角色(一個或多個角色)獲取權限,因此,對單個用戶權限的管理就變成了簡單地為用戶帳戶分配適當角色的問題。這簡化了常見操作,例如添加用戶或更改用戶部門。
1、角色分配:僅當對象已選擇或分配了角色時,對象才能行使權限。
2、角色授權:必須為主體授權主體的活動角色。使用上面的規則1,此規則可確保用戶只能承擔獲得其授權的角色。
3、權限授權:僅當對象的活動角色被授權時,對象才能行使權限。使用規則1和2,此規則可確保用戶只能行使其被授權的權限。
菜單
public class SysMenu { /// <summary> /// 父級 /// </summary> public int ParentId { get; set; } = 0; /// <summary> /// 菜單名稱 /// </summary> [StringLength(20)] public string Name { get; set; } /// <summary> /// 菜單地址 /// </summary> [StringLength(20)] [Required] public string Url { get; set; } /// <summary> /// 層級 /// </summary> [Column(TypeName = "tinyint(4)")] public int Level { get; set; } = 1; /// <summary> /// 菜單權限(list<int /> json) /// </summary> [StringLength(100)] public string Operates { get; set; } /// <summary> /// 排序 /// </summary> public int Sort { get; set; } /// <summary> /// 菜單圖標 /// </summary> public string Icon { get; set; } }
功能
public class SysOperate { /// <summary> /// 按鈕名稱 /// </summary> [StringLength(20)] [Required] public string Name { get; set; } /// <summary> /// 備註 /// </summary> [StringLength(int.MaxValue)] public string Remark { get; set; } /// <summary> /// 唯一標識 /// </summary> [Required] public int Unique { get; set; } }
角色
public class SysRole { /// <summary> /// 角色名稱 /// </summary> [StringLength(20)] [Required] public string Name { get; set; } /// <summary> /// 備註 /// </summary> [StringLength(int.MaxValue)] public string Remark { get; set; } }
用戶
public class SysUser { /// <summary> /// 角色id /// </summary> public int RoleId { get; set; } /// <summary> /// 用戶名 /// </summary> [StringLength(32)] [Required] public string UserName { get; set; } /// <summary> /// 密碼 /// </summary> [StringLength(500)] [Required] public string Password { get; set; } }
在日常工作中,總會有很多系統要做,每個系統都要一套完整的權限功能,有現成的直接拿來粘貼複製,沒有現成的又要浪費很多時間去設計實現它。 如果有這樣一個服務,我們可以節省很多不必要的粘貼複製操作,節省很多時間。
於是 ketchup.zero 這樣一個服務就誕生了。它是基於ketchu微服務框架來實現的一個權限授權服務,基本可以滿足我們日常工作的的權限需求。
服務的前端是基於vue的模板d2admin 開發的。
登陸
面板
用戶配置角色
菜單設置擁有那些權限
權限/功能/按鈕 管理
角色設置權限
如果它對你有幫助,請給一波start
服務 ketchup.zero 源碼地址:https://github.com/simple-gr/ketchup.zero
微服務框架 ketchup 源碼地址:https://github.com/simple-gr/ketchup
ketchup 交流群:592407137
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※新北清潔公司,居家、辦公、裝潢細清專業服務
※別再煩惱如何寫文案,掌握八大原則!
※教你寫出一流的銷售文案?
※超省錢租車方案
原文鏈接:https://fuckcloudnative.io/posts/lens/
Kubernetes 的桌面客戶端有那麼幾個,曾經 Kubernetic 應該是最好用的,但最近有個叫 Lens 的 APP 改變了這個格局,功能比 Kubernetic 多,使用體驗更好,適合廣大系統重啟工程師裝逼。它有以下幾個亮點:
① Lens 就是一個強大的 IDE,可以實時查看集群狀態,實時查看日誌流,方便排查故障。有了 Lens,你可以更方便快捷地使用你的集群,從根本上提高工作效率和業務迭代速度。
日誌流界面可以選擇显示或隱藏時間戳,也可以指定显示的行數:
② Lens 可以管理多集群,它使用內置的 kubectl 通過 kubeconfig 來訪問集群,支持本地集群和外部集群(如EKS、AKS、GKE、Pharos、UCP、Rancher 等),甚至連 Openshift 也支持:
只是與 Openshift 的監控還不太兼容。也可以很輕鬆地查看並編輯 CR:
有了 Lens,你就可以統一管理所有的集群。
③ Lens 內置了資源利用率的儀錶板,支持多種對接 Prometheus 的方式:
④ Lens 內置了 kubectl,它的內置終端會確保集群的 API Server 版本與 kubectl 版本兼容,所以你不需要在本地安裝 kubectl。可以驗證一下:
你會看到本地安裝的 kubectl 版本和 Lens 裏面打開的終端里的 kubectl 版本信息是不一樣的,Lens 確實內置了 kubectl。
⑤ Lens 內置了 helm 模板商店,可直接點擊安裝:
現在 Lens 迎來了最新版 3.5.0,換上了全新的 Logo:
穩定性也提升了很多,快去試試吧。
Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs加載問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
日本汽車大廠日產汽車(Nissan)10 日宣佈,旗下中國大陸合資公司東風汽車有限公司的乘用車部門「東風日產乘用車公司(以下稱東風日產)」自 10 日起將在大陸開賣東風日產自有品牌電動車「Venucia e30」,售價為 26 萬 7,800 元人民幣,目標為在 2018 年於中國電動車市場拿下 20% 市佔率。 Venucia e30 是以日產於 2010 年在日本開賣的電動車「Leaf」的車台、技術為根基,由日產與東風日產所攜手研發的車款,而日產也將成為第一家進軍中國電動車市場的日系車廠。 Venucia e30 初期將在北京、上海、廣州、深圳、大連、武漢、天津、鄭州和杭洲等 9 個都市販售,並計劃在 2015 年將販售區域擴及至中國全國。 據日本媒體共同通信指出,Venucia e30 約 4 小時可充飽電、充飽電狀態下的行駛距離為 175km;Venucia e30 將在廣州生產、2018 年銷售目標為 5 萬台。 (圖片來源:)
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
Java虛擬機把描述類的數據從Class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這個過程被稱為虛擬機的類加載機制。
一個類型從被加載到虛擬機內存中開始,到卸載除內存為止,它的生命周期將會經歷加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和 卸載(Unloading)、七個階段,其中驗證、準備、解析三個部分統稱為連接(Linking)。
類的生命周期如下圖:
其實加載、驗證、準備、初始化和卸載這五個階段的順序是確定的,類型的加載過程必須按照這種順序按部就班地開始,而解析階段則不一定:它在某些情況下可以在初始化階段之後再開始,這是為了支持Java語音的運行時綁定特性(也稱為動態綁定或晚期綁定)。
在什麼情況下需要開始類加載過程的第一個階段“加載”,《Java虛擬機規則》中並沒有進行強制約束,但是對於初始化階段《Java虛擬機規範》則是嚴格規定了有且只有以下六種情況必須立即對類進行“初始化”。
new、getstatic、putstatic或invokestatic這四條字節碼指令時,如果類型沒有進行過初始化,則需要先觸發其初始化階段。java.lang.reflect 包的方法對類型進行反射調用的時候,如果類型沒有進行過初始化,則需要先觸發其初始化。java.lang.invoke.MethodHandle實例最後的解析結果為REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四種類型的方法句柄,並且這個方法句柄對應的類沒有進行過初始化,則需要先觸發其初始化。default關鍵字修飾的接口方法)時,如果這個接口的實現類發生了初始化,那該接口要在其之前被初始化。父類
package com.jimoer.classloading;
/**
* @author jimoer
* @date Create in 2020/06/24 16:08
* @description 通過子類引用父類的靜態字段,不會導致子類初始化。
*/
public class FatherClass {
static {
System.out.println("FatherClass init!!!!!");
}
public static int value = 666;
}
子類
package com.jimoer.classloading;
public class SonClass extends FatherClass{
static {
System.out.println("SonClass init!!!");
}
}
測試類
@Test
public void testInitClass(){
System.out.println(SonClass.value);
}
運行結果:
FatherClass init!!!!!
666
通過運行結果我們看到,只輸出了“FatherClass init!!!!!”,並沒有輸出“SubClass init!!!”,這是因為對於使用靜態字段,只有直接定義這個字段的類才會被初始化,因此通過子類來引用父類中定義的靜態字段,並不會初始化子類。
/**
* 通過數組定義來引用類,不會觸發此類的初始化
*/
@Test
public void testInitClass2(){
FatherClass[] fathers = new FatherClass[5];
}
運行結果:未打印任何信息。
通過運行結果我們發現,並沒有打印出 FatherClass init!!!!! ,這說明並沒有觸發Father類的初始化階段。但是這段代碼裏面觸發了另一個名為“[Lcom.jimoer.classloading.FatherClass”的類的初始化階段,它是一個由虛擬機自動生成的、直接繼承與java.lang.Object的子類,創建動作由字節碼newarray觸發。這個類代表了一個元素類型為FatherClass的一維數組,數組中應用的屬性和方法(length屬性和clone()方法)都實現在這個類里。
/**
* @author jimoer
* 常量在編譯階段會存入調用類的常量池中,
* 本質上沒有直接引用到定義常量的類,
* 因此不會觸發定義常量的類的初始化。
*/
public class ConstantClass {
static {
System.out.println("ConstantClass init !!!");
}
public static final String CLASS_LOAD = "class load test !!!";
}
使用
/**
* 使用常量
*/
@Test
public void testInitClass3(){
System.out.println(ConstantClass.CLASS_LOAD);
}
運行結果:
class load test !!!
通過運行結果,我們看到當在使用一個類的常量時,並不會初始化定義了常量的類。這是因為雖然在Java源碼中確實引用了ConstatClass的類的常量CLASS_LOAD,但其實在編譯階段通過常量傳播優化,已經將此常量的值“class load test !!!”直接存儲在使用常量的類中的常量池中了,所以在使用ConstantClass.CLASS_LOAD時候,實際上都被轉化為在使用類自身的常量池的引用了。
接口也是有初始化過程的,上面的代碼都是用靜態語句塊“static {}”來輸出初始化信息的,而接口中不能使用static{}語句塊,但編譯器仍然會為接口生成“ ()”類構造器,用於初始化接口中所定義的成員變量。
還有一點接口與類不同,當一個類在初始化時,要求其父類全部都已經初始化過了,但是在一個接口初始化時,並不要求其父接口全部都完成了初始化,只有在真正使用到父接口的時候(例如引用接口中的常量)才會初始化。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※Google地圖已可更新顯示潭子電動車充電站設置地點!!
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※別再煩惱如何寫文案,掌握八大原則!
上周,高盛分析師派翠克•阿爾尚博(Patrick Archambault)指出,特斯拉或許需要再投入60億美元現金(尤其在2017年至2025年之間),才能實現“到2020年電動汽車的年產量達到50萬輛”的目標,從而顛覆汽車市場。 而特斯拉希望在明年年底前交付10萬輛電動汽車,其中包括Model S和即將推出的Model X。阿爾尚博預測,特斯拉要實現既定目標,到2025年為止將需要生產180萬至320萬輛電動汽車。但是,屆時如果特斯拉未能實現這些生產目標,電池工廠所生產的多餘電池將可能最終由太陽能公司SolarCity所消化。 特斯拉已經為SolarCity生產了少量的蓄電元件,超級電池工廠竣工後將滿足SolarCity部分或全部的耗電需求。馬斯克表示,兩家公司能以獨特的方式相互相容。如果更多的美國人能接受太陽能用於住宅和商業供電,特斯拉及其電池製造合作夥伴松下就能把超級電池工廠過剩產能所餘下的蓄電元件提供給SolarCity。超級電池工廠每年將為特斯拉生產50萬件電池組,因此,特斯拉不打算成為SolarCity蓄電組件的主要供應商。但如果特斯拉達不到生產目標,超級電池工廠就可能為SolarCity多出出力。
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
# 显示 Docker 版本信息
docker version
# 显示系統信息,包括鏡像和容器的數量
docker info
# 查看幫助文檔 幫助文檔地址:https://docs.docker.com/reference/
docker [命令] --help
docker images 查看最近創建的鏡像
docker images [OPTIONS] [REPOSITORY[:TAG]]
# 幫助文檔
[root@hwh1 ~]# docker images --help
Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]
List images
Options:
-a, --all Show all images (default hides intermediate images) 显示所有鏡像
--digests Show digests 显示摘要
-f, --filter filter Filter output based on conditions provided 根據提供的條件過濾輸出
--format string Pretty-print images using a Go template 用 Go 模板打印出一個圖像
--no-trunc Don't truncate output 不截斷輸出
-q, --quiet Only show numeric IDs 只显示数字 ID
# 查看最近創建的鏡像
# REPOSITORY 鏡像的倉庫源
# TAG 鏡像的標籤
# IMAGE ID 鏡像的id
# CREATED 鏡像的創建時間
# SIZE 鏡像的大小
[root@hwh1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 5 months ago 13.3kB
# 查看所有鏡像
[root@hwh1 ~]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 5 months ago 13.3kB
# 只显示数字 ID
[root@hwh1 ~]# docker images -q
bf756fb1ae65
docker search 搜索鏡像
docker search [OPTIONS] TERM
[root@hwh1 ~]# docker search --help
Usage: docker search [OPTIONS] TERM
Search the Docker Hub for images
Options:
-f, --filter filter Filter output based on conditions provided 根據提供的條件過濾輸出
--format string Pretty-print search using a Go template 用 Go 模板打印出一個圖像
--limit int Max number of search results (default 25) 搜索結果的最大值限制
--no-trunc Don't truncate output 不截斷輸出
[root@hwh1 ~]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 9626
docker pull 下載鏡像
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
[root@hwh1 ~]# docker pull --help
Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST]
Pull an image or a repository from a registry
Options:
-a, --all-tags Download all tagged images in the repository 下載倉庫中標記所有的鏡像,拿來選擇版本
--disable-content-trust Skip image verification (default true) 跳過圖像驗證
--platform string Set platform if server is multi-platform capable 如果服務器支持多平台,則設置平台
-q, --quiet Suppress verbose output 禁止詳細輸出
# 下載鏡像
[root@hwh1 ~]# docker pull mysql
Using default tag: latest # 版本信息(默認不設置tag,則為最新版)
latest: Pulling from library/mysql
8559a31e96f4: Pull complete # 分層下載,docker image 的核心,聯合文件系統
d51ce1c2e575: Pull complete
c2344adc4858: Pull complete
fcf3ceff18fc: Pull complete
16da0c38dc5b: Pull complete
b905d1797e97: Pull complete
4b50d1c6b05c: Pull complete
c75914a65ca2: Pull complete
1ae8042bdd09: Pull complete
453ac13c00a3: Pull complete
9e680cd72f08: Pull complete
a6b5dc864b6c: Pull complete
Digest: sha256:8b7b328a7ff6de46ef96bcf83af048cb00a1c86282bfca0cb119c84568b4caf6 # 簽名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真實地址
docker rmi 刪除鏡像
docker rmi [OPTIONS] IMAGE [IMAGE...]
[root@hwh1 ~]# docker rmi --help
Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
Remove one or more images
Options:
-f, --force Force removal of the image 強制刪除鏡像
--no-prune Do not delete untagged parents 不刪除未標記的父類
# 刪除指定鏡像
[root@hwh1 ~]# docker rmi mysql
Untagged: mysql:latest
Untagged: mysql@sha256:8b7b328a7ff6de46ef96bcf83af048cb00a1c86282bfca0cb119c84568b4caf6
Deleted: sha256:be0dbf01a0f3f46fc8c88b67696e74e7005c3e16d9071032fa0cd89773771576
Deleted: sha256:086d66e8d1cb0d52e9337eabb11fb9b95960e2e1628d90100c62ea5e8bf72306
Deleted: sha256:f37c61ee1973b18c285d0d5fcf02da4bcdb1f3920981499d2a20b2858500a110
Deleted: sha256:e40b8bca7dc63fc8d188a412328e56caf179022f5e5d5b323aae57d233fb1069
Deleted: sha256:339f6b96b27eb035cbedc510adad2560132925a835f0afddbcc1d311c961c14b
Deleted: sha256:d38b06cdb26a5c98857ddbc6ef531d3f57b00e325c0c314600b712efc7ff6ab0
Deleted: sha256:09687cd9cdf4c704fde969fdba370c2d848bc614689712bef1a31d0d581f2007
Deleted: sha256:b704a4a65bf536f82e5d8b86e633d19185e26313de8380162e778feb2852011a
Deleted: sha256:c37206160543786228aa0cce738e85343173851faa44bb4dc07dc9b7dc4ff1c1
Deleted: sha256:12912c9ec523f648130e663d9d4f0a47c1841a0064d4152bcf7b2a97f96326eb
Deleted: sha256:57d29ad88aa49f0f439592755722e70710501b366e2be6125c95accc43464844
Deleted: sha256:b17c024283d0302615c6f0c825137da9db607d49a83d2215a79733afbbaeb7c3
Deleted: sha256:13cb14c2acd34e45446a50af25cb05095a17624678dbafbcc9e26086547c1d74
# 遞歸刪除(批量刪除)
[root@hwh1 ~]# docker rmi -f $(docker images -aq)
Untagged: hello-world:latest
Untagged: hello-world@sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1
Deleted: sha256:bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b
# 已全部刪除
[root@hwh1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
注:下載一個 centos 鏡像測試
docker run 新建容器並啟動
[root@hwh1 ~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
8a29a15cefae: Pull complete
Digest: sha256:fe8d824220415eed5477b63addf40fb06c3b049404242b31982106ac204f6700
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest
docker run
[root@hwh1 ~]# docker run --help
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Run a command in a new container
Options:
-d, --detach Run container in background and print
container ID 後台方式運行
--name string Assign a name to the container 容器名字,來區分容器
-i, --interactive Keep STDIN open even if not attached 使用交互方式,進入容器查詢內容
-t, --tty Allocate a pseudo-TTY 使用交互方式,進入容器查詢內容
-p, --publish list Publish a container's port(s) to the host 指定容器端口
-p 主機端口:容器端口
-p 容器端口
-p ip:主機端口:容器端口
容器端口
-P, --publish-all Publish all exposed ports to random ports 隨機端口
# 啟動並進入容器,相當於一個小型虛擬機
[root@hwh1 ~]# docker run -it centos /bin/bash
[root@af833bdd3acf /]# ls # 基礎版 centos 很多命令都不完善
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
[root@af833bdd3acf /]# exit # 退出命令
exit
docker ps 列出所有正在運行的容器
docker ps [OPTIONS]
[root@hwh1 ~]# docker ps --help
Usage: docker ps [OPTIONS]
List containers
Options:
-a, --all Show all containers (default shows just running) 列出所有的容器,包括正在運行和停止的
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print containers using a Go template
-n, --last int Show n last created containers (includes all states) 列出最近運行的容器
(default -1)
-l, --latest Show the latest created container (includes all states) 显示最後創建的容器
--no-trunc Don't truncate output 不截斷輸出
-q, --quiet Only display numeric IDs 只显示数字 ID
-s, --size Display total file sizes 显示文件總大小
[root@hwh1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0f986785f33 centos "/bin/bash" 7 seconds ago Up 5 seconds nervous_agnesi
[root@hwh1 ~]# docker ps -n=1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0f986785f33 centos "/bin/bash" 6 minutes ago Up 6 minutes nervous_agnesi
[root@hwh1 ~]# docker ps -q
a0f986785f33
exit # 直接容器停止並退出
Ctrl + P + Q # 不停止容器退出(快捷鍵)
docker rm 刪除容器
docker rm [OPTIONS] CONTAINER [CONTAINER...]
[root@hwh1 ~]# docker rm --help
Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
Remove one or more containers
Options:
-f, --force Force the removal of a running container (uses SIGKILL) 強制刪除正在運行的容器
-l, --link Remove the specified link 刪除指定的鏈接
-v, --volumes Remove anonymous volumes associated with the container 刪除與容器關聯的匿名卷
[root@hwh1 ~]# docker rm af833bdd3acf 刪除已經停止的
af833bdd3acf
[root@hwh1 ~]# docker rm -f a0f986785f33 刪除正在運行的容器
a0f986785f33
# docker ps -a -q|xargs docker rm # 刪除所有的容器,使用管道符
docker start id # 啟動
docker restart id # 重啟
docker stop id # 停止當前正在運行的容器
docker kill id # 強制停止當前容器
[root@hwh1 ~]# docker start 7b28015cd7f6
7b28015cd7f6
[root@hwh1 ~]# docker restart 7b28015cd7f6
7b28015cd7f6
[root@hwh1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b28015cd7f6 centos "/bin/bash" 46 seconds ago Up 9 seconds unruffled_wiles
e2ff2fee0669 bf756fb1ae65 "/hello" 12 days ago Exited (0) 12 days ago amazing_nightingale
690a9f41c7a8 bf756fb1ae65 "/hello" 12 days ago Exited (0) 12 days ago zealous_blackwell
[root@hwh1 ~]# docker stop 7b28015cd7f6
7b28015cd7f6
[root@hwh1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b28015cd7f6 centos "/bin/bash" 57 seconds ago Exited (0) 2 seconds ago unruffled_wiles
e2ff2fee0669 bf756fb1ae65 "/hello" 12 days ago Exited (0) 12 days ago amazing_nightingale
690a9f41c7a8 bf756fb1ae65 "/hello" 12 days ago Exited (0) 12 days ago
# docker run -d 鏡像名
[root@hwh1 ~]# docker run -d centos
9e34ebe17e41fb762f535ab21d81240b5fb4b105a44ed13c8813a8a8978f9b27
# 問題:
# docker ps -a,發現服務停止了
# 常見的坑:
# docker 容器使用後台運行,就必須要有要一個前台進程,docker發現沒有應用,就會自動停止
docker logs [OPTIONS] CONTAINER
[root@hwh1 ~]# docker logs --help
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
Options:
--details Show extra details provided to logs 显示額外的詳細信息
-f, --follow Follow log output 跟蹤日誌輸出
--since string Show logs since timestamp (e.g. 2013-01-02T13:23:37) or 從時間戳開始显示
relative (e.g. 42m for 42 minutes)
--tail string Number of lines to show from the end of the logs (default 日誌显示行數
"all")
-t, --timestamps Show timestamps 显示時間戳
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) 在時間戳之前显示日誌
or relative (e.g. 42m for 42 minutes)
docker top CONTAINER [ps OPTIONS]
[root@hwh1 ~]# docker top --help
Usage: docker top CONTAINER [ps OPTIONS]
Display the running processes of a container
# docker top 容器id
[root@hwh1 ~]# docker top 147f08710d27
UID PID PPID C STIME
root 76123 76105 0 21:13
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
[root@hwh1 ~]# docker inspect --help
Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...]
Return low-level information on Docker objects
Options:
-f, --format string Format the output using the given Go template 用 Go 模板打印出一個圖像
-s, --size Display total file sizes if the type is container 如果類型是容器的話,就显示容器大小
--type string Return JSON for specified type 返回指定類型的 JSON 字符串
# 查看 centos 的元數據
[root@hwh1 ~]# docker inspect 147f08710d27
[
{
"Id": "147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084",
"Created": "2020-06-15T13:13:13.783652979Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 76123,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-06-15T13:13:15.632825635Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:470671670cac686c7cf0081e0b37da2e9f4f768ddc5f6a26102ccd1c6954c1ee",
"ResolvConfPath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/hostname",
"HostsPath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/hosts",
"LogPath": "/var/lib/docker/containers/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084/147f08710d2732d81ee9ce2680a7cfad48cbd186e87e27b081d82c103a29f084-json.log",
"Name": "/dazzling_benz",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd-init/diff:/var/lib/docker/overlay2/ae0a1afad34903571dd0df8a39bc4bea93ccd793ae2f6185fa95385c18d56f05/diff",
"MergedDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd/merged",
"UpperDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd/diff",
"WorkDir": "/var/lib/docker/overlay2/74794286462edce8a73f8e74239c0229d6cec3afac92f052951245d91e05c7cd/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "147f08710d27",
"Domainname": "",
"User": "",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"Tty": true,
"OpenStdin": true,
"StdinOnce": true,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20200114",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS",
"org.opencontainers.image.created": "2020-01-14 00:00:00-08:00",
"org.opencontainers.image.licenses": "GPL-2.0-only",
"org.opencontainers.image.title": "CentOS Base Image",
"org.opencontainers.image.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "dcbcaf21dc6395481ce4c27bd58e83b306aee13216f852b4ac92edab13dc6698",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/dcbcaf21dc63",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "1b8456cbbb162e74762144d5a13305ba84acb45db92ce2467c0bc15724077b72",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "23077e8fffbf9407b9d83e492e05cc11904b4dbf7fd3ab3a4b84c36c1a7ee4a5",
"EndpointID": "1b8456cbbb162e74762144d5a13305ba84acb45db92ce2467c0bc15724077b72",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
# 我們通常容器都是使用後台方式運行的,需要進入容器,修改一些配置
# 方式一 :docker exec -it 容器id bashShell
# 進入容器后開啟一個新的終端,可以在裏面操作(常用)
# docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
[root@hwh1 ~]# docker exec --help
Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
Run a command in a running container
Options:
-d, --detach Detached mode: run command in the background 在後台運行命令
--detach-keys string Override the key sequence for detaching a container 重寫用於分離容器的鍵序列
-e, --env list Set environment variables 設置環境變量
-i, --interactive Keep STDIN open even if not attached 即使沒有連接,也保持STDIN打開
--privileged Give extended privileges to the command 授予命令擴展權限
-t, --tty Allocate a pseudo-TTY 分配一個偽TTY
-u, --user string Username or UID (format: <name|uid>[:<group|gid>]) 用戶名或者 id
-w, --workdir string Working directory inside the container 容器內的工作目錄
[root@hwh1 ~]# docker exec -it a41c80fd6d1c /bin/bash
[root@a41c80fd6d1c /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
# 方式二 :docker attach 容器id
# 進入容器正在執行的終端,不會啟動新的終端
# docker attach [OPTIONS] CONTAINER
[root@hwh1 ~]# docker attach --help
Usage: docker attach [OPTIONS] CONTAINER
Attach local standard input, output, and error streams to a running container
Options:
--detach-keys string Override the key sequence for detaching a container 重寫用於分離容器的鍵序列
--no-stdin Do not attach STDIN 不要附加STDIN
--sig-proxy Proxy all received signals to the process (default true) 將所有接收到的信號代理到進程(默認為true)
[root@hwh1 ~]# docker attach a41c80fd6d1c
[root@a41c80fd6d1c /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
# 從容器被拷貝文件到主機上
# docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- docker cp 容器id:容器內路徑 目的的主機路徑
# 從主機上拷貝文件到容器
# docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH docker cp 主機路徑 容器id:目的的容器內路徑
[root@hwh1 ~]# docker cp --help
Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
Copy files/folders between a container and the local filesystem
Use '-' as the source to read a tar archive from stdin
and extract it to a directory destination in a container.
Use '-' as the destination to stream a tar archive of a
container source to stdout.
Options:
-a, --archive Archive mode (copy all uid/gid information) 存檔模式(複製所有uid/gid信息)
-L, --follow-link Always follow symbol link in SRC_PATH 始終遵循容器內路徑中的符號鏈接
# 從容器被拷貝文件到主機上
[root@hwh1 home]# docker attach a41c80fd6d1c
[root@a41c80fd6d1c /]# cd /home
[root@a41c80fd6d1c home]# ls
[root@a41c80fd6d1c home]# touch hwh.java # 在 home 目錄下創建一個 hwh.java
[root@a41c80fd6d1c home]# ls
hwh.java
[root@hwh1 home]# ls
hwh hwh1 hwh2 user01 user02
[root@hwh1 home]# docker cp a41c80fd6d1c:/home/hwh.java /home # 將 hwh.java 複製到主機上
[root@hwh1 home]# ls
hwh hwh1 hwh2 hwh.java user01 user02
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
摘錄自2019年10月17日中央社報導
菲律賓南部民答那峨島北可塔巴托省(North Cotabato)杜路南鎮(Tulunan)東南方約22公里處,16日7時37分發晚間發生規模6.3強震,震源深度僅15公里,附近省份都感受到地震震波。已知造成2人死亡,至少20多人受傷。ABS-CBN新聞網報導,根據菲律賓火山暨地震研究所(Phivolcs)資訊,這起地震沒有海嘯風險。美國地質研究所測得地震規模為6.4。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案