答題卡識別改分項目

目錄

核心思路

分步實現與代碼解析

1. 環境準備與工具函數定義

2. 圖片預處理

3. 輪廓提取與篩選

3. 輪廓提取與篩選

4. 透視變換(矯正傾斜答題卡)

5. 閾值處理(突出填涂區域)

6. 提取選項圓圈輪廓

7. 選項輪廓排序(按題目順序排列)


在日常教學與考試場景中,人工批改答題卡不僅耗時耗力,還容易因主觀疲勞導致誤判。本篇將基于 OpenCV 實現全自動答題卡識別與改分,通過圖像處理技術精準提取答案區域、比對標準答案,并自動計算得分,大幅提升批改效率與準確性。

核心思路

答題卡識別改分的核心是 “從圖像中精準定位有效信息并與標準對比”,整體流程分為 9 個關鍵步驟:

  1. 圖片預處理(去噪、增強)
  2. 邊緣檢測(突出答題卡輪廓)
  3. 輪廓提取與篩選(定位答題卡主體)
  4. 輪廓近似(確定答題卡四角,為透視變換做準備)
  5. 透視變換(將傾斜答題卡矯正為正視圖)
  6. 閾值處理(將圖像轉為 “非黑即白”,突出填涂區域)
  7. 選項圓圈輪廓提取(定位每道題的 5 個選項)
  8. 答案比對(識別填涂選項,與標準答案匹配)
  9. 分數計算(統計正確率,生成最終得分)

分步實現與代碼解析

項目答題卡如下:

1. 環境準備與工具函數定義

首先導入所需庫,并定義圖像顯示函數(方便中間結果查看):

import cv2
import numpy as np# 圖像顯示函數:接收窗口名和圖像,按任意鍵關閉窗口
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)  # 等待按鍵輸入(0表示無限等待)cv2.destroyWindow(name)  # 關閉當前窗口

2. 圖片預處理

原始圖像可能存在噪聲、色彩干擾,預處理的目標是 “簡化圖像信息,突出關鍵邊緣”,步驟包括:

  • 灰度化:將彩色圖像轉為單通道灰度圖,減少計算量
  • 高斯濾波:通過平滑處理去除高頻噪聲(如紙張紋理、拍攝噪點)
  • 邊緣檢測:用 Canny 算法提取圖像邊緣,為后續輪廓定位做準備
"""-----1. 圖片預處理-----"""
# 讀取答題卡圖像(替換為你的圖像路徑)
image = cv2.imread(r'./images/answer_sheet_01.jpg')
contours_img = image.copy()  # 備份原始圖像,用于后續繪制輪廓# 1.1 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # BGR轉灰度(OpenCV默認讀取格式為BGR)
# 1.2 高斯濾波(5x5卷積核,標準差0,平衡去噪與邊緣保留)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
cv_show('Gaussian Blur (去噪后)', blurred)  # 查看去噪效果
# 1.3 Canny邊緣檢測(閾值1=75,閾值2=200,僅保留對比度高的邊緣)
edged = cv2.Canny(blurred, 75, 200)
cv_show('Canny Edges (邊緣檢測結果)', edged)  # 查看邊緣檢測效果

3. 輪廓提取與篩選

邊緣檢測后,需要從邊緣圖中提取閉合輪廓,并篩選出 “答題卡主體輪廓”(通常為矩形,即 4 個頂點):

"""-----2. 輪廓提取與篩選-----"""
# 2.1 提取輪廓(RETR_EXTERNAL:僅保留最外層輪廓;CHAIN_APPROX_SIMPLE:簡化輪廓點)
# OpenCV 3.x返回值為 (_, cnts, _),OpenCV 4.x返回值為 (cnts, _),此處兼容3.x
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
# 2.2 繪制所有輪廓(紅色,線寬3),查看輪廓提取效果
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3)
cv_show('All Contours (所有輪廓)', contours_img)# 2.3 篩選答題卡輪廓(按面積降序排序,優先保留大面積輪廓)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
doc_cnt = None  # 存儲答題卡的最終輪廓for c in cnts:# 計算輪廓周長(True表示輪廓閉合)peri = cv2.arcLength(c, True)# 輪廓近似(0.02*peri:近似精度,值越小越接近原始輪廓)approx = cv2.approxPolyDP(c, 0.02 * peri, True)# 答題卡為矩形,近似后輪廓應包含4個頂點if len(approx) == 4:doc_cnt = approxbreak# 繪制篩選出的答題卡輪廓(綠色,線寬2)
cv2.drawContours(image, [doc_cnt], -1, (0, 255, 0), 2)
cv_show('Answer Sheet Contour (答題卡輪廓)', image)

輪廓入戲:

3. 輪廓提取與篩選

邊緣檢測后,需要從邊緣圖中提取閉合輪廓,并篩選出 “答題卡主體輪廓”(通常為矩形,即 4 個頂點):

"""-----2. 輪廓提取與篩選-----"""
# 2.1 提取輪廓(RETR_EXTERNAL:僅保留最外層輪廓;CHAIN_APPROX_SIMPLE:簡化輪廓點)
# OpenCV 3.x返回值為 (_, cnts, _),OpenCV 4.x返回值為 (cnts, _),此處兼容3.x
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
# 2.2 繪制所有輪廓(紅色,線寬3),查看輪廓提取效果
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3)
cv_show('All Contours (所有輪廓)', contours_img)# 2.3 篩選答題卡輪廓(按面積降序排序,優先保留大面積輪廓)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
doc_cnt = None  # 存儲答題卡的最終輪廓for c in cnts:# 計算輪廓周長(True表示輪廓閉合)peri = cv2.arcLength(c, True)# 輪廓近似(0.02*peri:近似精度,值越小越接近原始輪廓)approx = cv2.approxPolyDP(c, 0.02 * peri, True)# 答題卡為矩形,近似后輪廓應包含4個頂點if len(approx) == 4:doc_cnt = approxbreak# 繪制篩選出的答題卡輪廓(綠色,線寬2)
cv2.drawContours(image, [doc_cnt], -1, (0, 255, 0), 2)
cv_show('Answer Sheet Contour (答題卡輪廓)', image)

4. 透視變換(矯正傾斜答題卡)

實際拍攝的答題卡可能存在傾斜,透視變換可將 “傾斜的矩形” 轉為 “正對著鏡頭的矩形”,方便后續選項定位:

  • 第一步:定義order_points函數,將 4 個頂點按 “左上→右上→右下→左下” 排序
  • 第二步:定義four_point_transform函數,計算透視變換矩陣并應用變換
"""-----3. 透視變換(矯正答題卡)-----"""
def order_points(pts):"""將4個頂點按“左上(tl)→右上(tr)→右下(br)→左下(bl)”排序"""rect = np.zeros((4, 2), dtype="float32")  # 初始化排序后的坐標# 1. 左上點:x+y最小;右下點:x+y最大s = pts.sum(axis=1)  # 每個點的x+y求和rect[0] = pts[np.argmin(s)]  # 左上(tl)rect[2] = pts[np.argmax(s)]  # 右下(br)# 2. 右上點:x-y最小;左下點:x-y最大diff = np.diff(pts, axis=1)  # 每個點的x-y差值(axis=1:按行計算后一列減前一列)rect[1] = pts[np.argmin(diff)]  # 右上(tr)rect[3] = pts[np.argmax(diff)]  # 左下(bl)return rectdef four_point_transform(image, pts):"""透視變換:將傾斜的答題卡轉為正視圖"""# 步驟1:獲取排序后的4個頂點rect = order_points(pts)tl, tr, br, bl = rect  # 解包頂點坐標# 步驟2:計算目標圖像的寬度和高度(取最大值確保覆蓋完整答題卡)# 寬度:右下→左下 的水平距離 / 右上→左上 的水平距離width_a = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))width_b = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))max_width = max(int(width_a), int(width_b))  # 目標寬度# 高度:右上→右下 的垂直距離 / 左上→左下 的垂直距離height_a = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))height_b = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))max_height = max(int(height_a), int(height_b))  # 目標高度# 步驟3:定義目標圖像的4個頂點(正視圖的四個角)dst = np.array([[0, 0],                  # 左上[max_width - 1, 0],      # 右上(-1是因為像素索引從0開始)[max_width - 1, max_height - 1],  # 右下[0, max_height - 1]      # 左下], dtype="float32")# 步驟4:計算透視變換矩陣M,應用變換得到正視圖M = cv2.getPerspectiveTransform(rect, dst)  # 生成3x3變換矩陣warped = cv2.warpPerspective(image, M, (max_width, max_height))  # 執行變換return warped# 執行透視變換(doc_cnt是答題卡的4個頂點,需轉為float32格式)
warped = four_point_transform(image, doc_cnt.reshape(4, 2))
cv_show('Warped Sheet (矯正后答題卡)', warped)

5. 閾值處理(突出填涂區域)

矯正后的答題卡仍為灰度圖,通過 “閾值二值化” 將圖像轉為 “非黑即白”,讓填涂的選項(深色)與空白選項(白色)對比更強烈:

"""-----4. 閾值處理(突出填涂區域)-----"""
# 5.1 將矯正后的彩色圖轉為灰度圖
warped_gray = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
# 5.2 二值化(THRESH_BINARY_INV:黑白反轉;THRESH_OTSU:自動計算最佳閾值)
# 效果:填涂區域為白色(255),空白區域為黑色(0)
thresh = cv2.threshold(warped_gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv_show('Thresholded (二值化結果)', thresh)# 備份二值化圖像,用于后續繪制選項輪廓
thresh_copy = thresh.copy()

6. 提取選項圓圈輪廓

答題卡每道題包含 5 個圓形選項,需從二值化圖中提取這些圓圈輪廓,并篩選出 “符合選項大小” 的輪廓:

"""-----5. 提取選項圓圈輪廓-----"""
# 6.1 提取二值化圖中的所有輪廓(僅保留最外層輪廓)
option_cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
# 6.2 繪制所有輪廓(綠色,線寬1),查看選項定位效果
warped_with_options = cv2.drawContours(warped.copy(), option_cnts, -1, (0, 255, 0), 1)
cv_show('All Option Contours (所有選項輪廓)', warped_with_options)# 6.3 篩選“有效選項輪廓”(排除過小/過扁的干擾輪廓)
valid_option_cnts = []
for c in option_cnts:# 獲取輪廓的邊界矩形(x:左上角x坐標,y:左上角y坐標,w:寬度,h:高度)x, y, w, h = cv2.boundingRect(c)# 計算寬高比(圓形的寬高比接近1)aspect_ratio = w / float(h)# 篩選條件:寬度≥20px、高度≥20px、寬高比0.9~1.1(接近圓形)if w >= 20 and h >= 20 and aspect_ratio >= 0.9 and aspect_ratio <= 1.1:valid_option_cnts.append(c)# 繪制篩選后的有效選項輪廓(紅色,線寬1)
warped_valid_options = cv2.drawContours(warped.copy(), valid_option_cnts, -1, (0, 0, 255), 1)
cv_show('Valid Option Contours (有效選項輪廓)', warped_valid_options)

? ? ? ? ? ? ? ?

7. 選項輪廓排序(按題目順序排列)

提取的選項輪廓可能雜亂無章,需按 “從上到下、從左到右” 排序,確保與題目順序對應:

"""-----6. 選項輪廓排序(按題目順序)-----"""
def sort_contours(cnts, method='left-to-right'):"""按指定方向排序輪廓:left-to-right(左右)、top-to-bottom(上下)"""reverse = False  # 是否反向排序axis = 0         # 排序依據的軸(0:x軸,1:y軸)# 1. 確定排序方向和軸if method in ['right-to-left', 'bottom-to-top']:reverse = True  # 反向排序(從右到左/從下到上)if method in ['top-to-bottom', 'bottom-to-top']:axis = 1  # 按y軸排序(上下方向)# 2. 為每個輪廓創建“邊界矩形”,按矩形的x/y軸坐標排序bounding_boxes = [cv2.boundingRect(c) for c in cnts]  # 每個輪廓的邊界矩形# 按“邊界矩形的指定軸”排序(zip:將輪廓與矩形綁定;sorted:按軸排序)cnts, bounding_boxes = zip(*sorted(zip(cnts, bounding_boxes),key=lambda b: b[1][axis],  # 排序鍵:矩形的axis軸坐標(x或y)reverse=reverse))return cnts, bounding_boxes# 7.1 先按“從上到下”排序(每道題的5個選項為一組)
sorted_option_cnts, _ = sort_contours(valid_option_cnts, method='top-to-bottom')
# 7.2 繪制排序后的輪廓(藍色,線寬1)
warped_sorted_options = cv2.drawContours(warped.copy(), sorted_option_cnts, -1, (255, 0, 0), 1)
cv_show('Sorted Option Contours (排序后選項輪廓)', warped_sorted_options)

8. 識別填涂答案與標準答案比對
核心邏輯:通過 “掩膜 + 像素計數” 識別每道題的填涂選項,再與標準答案對比,標記對錯:
? 掩膜(mask):為每個選項創建 “僅包含該選項的黑白圖”
? 像素計數:填涂選項的白色像素(255)數量遠多于空白選項,以此定位填涂位置

"""-----7. 答案識別與比對-----"""
# 8.1 定義標準答案(鍵:題序號0~4,值:正確選項序號0~4,對應每道題的5個選項)
ANSWER_KEY = {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}
correct_count = 0  # 正確題數
warped_result = warped.copy()  # 用于繪制結果的圖像# 8.2 按“每5個選項一組”遍歷(每道題對應5個選項)
for (question_idx, i) in enumerate(np.arange(0, len(sorted_option_cnts), 5)):# 取當前題的5個選項輪廓,按“從左到右”排序current_question_cnts, _ = sort_contours(sorted_option_cnts[i:i+5], method='left-to-right')bubbled_idx = None  # 存儲當前題的填涂選項序號(0~4)# 遍歷當前題的5個選項,找到填涂的選項for (option_idx, c) in enumerate(current_question_cnts):# 步驟1:為當前選項創建掩膜(僅該選項區域為白色,其余為黑色)mask = np.zeros(thresh.shape, dtype="uint8")cv2.drawContours(mask, [c], -1, 255, -1)  # -1表示填充輪廓內部# cv_show(f'Option {option_idx} Mask (選項{option_idx}掩膜)', mask)# 步驟2:掩膜與二值化圖做“與運算”,僅保留當前選項的填涂區域masked_thresh = cv2.bitwise_and(thresh, thresh, mask=mask)# cv_show(f'Masked Thresh (選項{option_idx}與運算結果)', masked_thresh)# 步驟3:計算白色像素數量(填涂區域的像素數)white_pixel_count = cv2.countNonZero(masked_thresh)# 步驟4:確定填涂選項(白色像素最多的選項即為填涂選項)if bubbled_idx is None or white_pixel_count > bubbled_idx[0]:bubbled_idx = (white_pixel_count, option_idx)  # (像素數, 選項序號)# 8.3 與標準答案比對,標記對錯correct_option_idx = ANSWER_KEY[question_idx]  # 當前題的正確選項序號if bubbled_idx[1] == correct_option_idx:# 正確:綠色輪廓(線寬2),正確題數+1color = (0, 255, 0)correct_count += 1else:# 錯誤:紅色輪廓(線寬2)color = (0, 0, 255)# 繪制當前題的正確選項輪廓(標記對錯)cv2.drawContours(warped_result, [current_question_cnts[correct_option_idx]], -1,

最終結果如下:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/99206.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/99206.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/99206.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python爬蟲實戰:研究Pandas,構建新浪網股票數據采集和分析系統

1. 系統概述 股票數據分析系統旨在通過自動化手段獲取市場數據,進行深度分析,輔助投資決策。本系統主要包含以下核心模塊: 數據爬取模塊:從新浪財經獲取股票列表、基本信息及歷史交易數據 數據處理模塊:清洗原始數據,處理缺失值與異常值,計算技術指標 分析可視化模塊:…

【C++STL】list的詳細用法和底層實現

&#x1f31f;個人主頁&#xff1a;第七序章 &#x1f308;專欄系列&#xff1a;C&#xff0b;&#xff0b; 目錄 ??前言&#xff1a; &#x1f308;一&#xff1a;介紹 &#x1f308;二&#xff1a;list的創建 ??基本框架 &#x1f319;節點類 &#x1f319;構造函…

AI大模型開發(多模態+提示詞)

接著之前的例子&#xff0c;繼續測試模型對話&#xff0c;今天主要測試多模態加上系統提示詞。 一.多模態 多模態方法&#xff0c;主要添加了對圖片的測試。 public String chatWithMessage(UserMessage userMessage){ChatResponse chatResponse qwenChatModel.chat(userMess…

Qt程序單獨運行報錯問題

Qt程序單獨運行報錯問題介紹問題原因分析解決方案&#xff08;從最佳實踐到臨時方法&#xff09;方法一&#xff1a;使用 windeployqt 工具&#xff08;最推薦、最規范&#xff09;方法二&#xff1a;臨時修改系統 PATH&#xff08;適合開發調試&#xff09;方法三&#xff1a;…

Flask學習筆記(二)--路由和變量

一、路由Flask支持兩種路由1、使用route()裝飾器將URL綁定到函數app.route(/hello)def hello_world():return hello world2、使用應用程序對象的add_url_rule()函數def hello_world():return hello worldapp.add_url_rule(/, hello, hello_world)二、變量規則Flask開發中&#…

Skywalking告警配置+簡易郵件告警應用配置(保姆級)

Skywalking告警配置簡易郵件告警應用配置前言&#xff1a; 前文&#xff1a;SkyWalking Elasticsearch8 容器化部署指南&#xff1a;國內鏡像加速與生產級調優_skywalkinges-CSDN博客 ? SKywalking Agent配置Oracle監控插件安裝指南-CSDN博客 Skywalking版本&#xff1a;V10.…

無人機如何實現圖傳:從原理到實戰的全景解讀

無人機圖傳的工作不是簡單地把鏡頭的數據直接“丟”到一個屏幕上&#xff0c;而是一個由編碼、傳輸、解碼三段組成的系統。首先是視頻編碼&#xff1a;攝像頭采集的原始畫面通常需要經過編解碼器壓縮&#xff0c;常見標準包括H.264、H.265和VP9等。壓縮的目的是減少數據量&…

AS32S601在軌重構(OTA)方案的優化與分析

摘要在軌重構&#xff08;OTA&#xff09;技術因其在航天、工業控制、物聯網等領域的高可靠性和持續服務需求而備受關注。本文以國科安芯推出的AS32S601芯片為研究對象&#xff0c;深入分析其OTA方案的設計原理、技術細節及優化策略&#xff0c;并結合芯片的硬件特性&#xff0…

修復Android studio的adb無法連接手機問題

復制下面的內容到一個文本txt里面然后把里面的Android studio路徑和sdk路徑改成你自己的&#xff0c;然后改成把.txt改成bat 右鍵管理員運行 echo off REM Deep Fix for "Couldnt terminate the existing process" error REM This script will completely reset ADB …

css優化都有哪些優化方案

CSS 優化其實可以分成幾個層面&#xff1a;性能優化、可維護性優化、兼容性優化以及用戶體驗優化。這里我幫你梳理一份比較系統的 CSS 優化方案清單&#xff0c;方便你參考&#xff1a;&#x1f539; 一、加載性能優化減少 CSS 文件體積壓縮 CSS&#xff08;去掉空格、換行、注…

vue,uniapp 實現卷簾對比效果

需求&#xff1a;兩張圖重疊放在一起&#xff0c;拖動分割線實現卷簾對比效果&#xff0c;如圖一、vue2代碼 <template><div class"main"><div class"img-comparison" mousedown"startSlide"><img class"before"…

【筆記】空氣彈簧概述、剛度調節原理

參考鏈接&#xff1a;汽車底盤空氣懸架關鍵零部件之空氣彈簧 1.概述 汽車空氣彈簧&#xff08;Air Spring&#xff09;是一種以“壓縮空氣”作為彈性介質的懸架元件&#xff0c;用來取代傳統鋼制螺旋彈簧或鋼板彈簧。它在乘用車、客車、重卡及軌道交通上越來越普及&#xff0…

UDP Socket 進階:從 Echo 到字典服務器,學會 “解耦” 網絡與業務

開篇&#xff1a;從 “回顯” 到 “字典”&#xff0c;核心變在哪&#xff1f;上一篇我們實現了 Echo 服務器 —— 網絡層和業務層是 “綁死” 的&#xff1a;網絡層收到數據后&#xff0c;直接把原數據發回去。但實際開發中&#xff0c;業務邏輯會復雜得多&#xff08;比如查字…

數據結構之復雜度

數據結構的理解 數據本身是雜亂無章的&#xff0c;需要結構進行增刪查改等操作更好的管理數據&#xff1b; 比如&#xff1a;在程序中需要將大量的代碼&#xff08;數據&#xff09;通過結構進行管理&#xff1b; 再比如&#xff1a;定義1000個整型變量的數組&#xff0c;我們…

運維安全06 - 服務安全

云計算服務安全 在當今數字化時代&#xff0c;各種服務&#xff08;如網絡應用、云計算平臺、數據庫系統等&#xff09;已成為我們日常生活和工作中不可或缺的一部分。 然而&#xff0c;隨著服務的廣泛應用&#xff0c;其安全性問題也日益凸顯。 一、服務安全 服務安全是一…

01數據結構-初探動態規劃

01數據結構-初探動態規劃前言1.基本思想2.重疊子問題3.斐波那契數列4.備忘錄&#xff08;記憶化搜索表&#xff09;4.1備忘錄&#xff08;記憶化搜索表&#xff09;代碼實現5.DP table5.1DP table代碼實現6.練習前言 在學習動態規劃時切忌望文生義&#xff0c;因為其名字與其思…

[智能算法]可微的神經網絡搜索算法-FBNet

一、概述 相較于基于強化學習的NAS&#xff0c;可微NAS能直接使用梯度下降更新模型結構超參數&#xff0c;其中較為有名的算法就是DARTS&#xff0c;其具體做法如下。 首先&#xff0c;用戶需要定義一些候選模塊&#xff0c;這些模塊內部結構可以互不相同&#xff08;如設置不同…

Elasticsearch安裝啟動常見問題全解析

文章目錄&#x1f4da; Elasticsearch 安裝與啟動問題總結一、核心問題概覽二、詳細問題分析與解決方案1. &#x1f510; **權限問題&#xff1a;AccessDeniedException**? 錯誤日志&#xff1a;&#x1f4cc; 原因&#xff1a;? 解決方案&#xff1a;2. ?? **配置沖突&…

Uniapp中使用renderjs實現OpenLayers+天地圖的展示與操作

Uniapp中自帶的地圖組件對支持的地圖服務略有局限&#xff0c;同時&#xff0c;該組件在樣式布局上層級過高且無法控制&#xff0c;無法滿足部分高度自定義化的需求。故引入renderjs視圖層工具搭配OpenLayers框架對地圖功能進行實現&#xff0c;但由于renderjs的限制&#xff0…

從C++開始的編程生活(8)——內部類、匿名對象、對象拷貝時的編譯器優化和內存管理

前言 本系列文章承接C語言的學習&#xff0c;需要有C語言的基礎才能學會哦~ 第8篇主要講的是有關于C的內部類、匿名對象、對象拷貝時的編譯器優化和內存管理。 C才起步&#xff0c;都很簡單&#xff01;&#xff01; 目錄 前言 內部類 性質 匿名對象 性質 ※對象拷貝時的…