成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

干貨|手把手教你用115行代碼做個數(shù)獨解析器!

你也是數(shù)獨愛好者嗎?

成都創(chuàng)新互聯(lián)長期為數(shù)千家客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為永清企業(yè)提供專業(yè)的成都網(wǎng)站建設、做網(wǎng)站,永清網(wǎng)站改版等技術(shù)服務。擁有10年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。

Aakash Jhawar和許多人一樣,樂于挑戰(zhàn)新的難題。上學的時候,他每天早上都要玩數(shù)獨。長大后,隨著科技的進步,我們可以讓計算機來幫我們解數(shù)獨了!只需要點擊數(shù)獨的圖片,它就會為你填滿全部九宮格。

叮~ 這里有一份數(shù)獨解析教程,等待你查收~ 喜歡收藏硬核干貨的小伙伴看過來~

我們都知道,數(shù)獨由9×9的格子組成,每行、列、宮各自都要填上1-9的數(shù)字,要做到每行、列、宮里的數(shù)字都不重復。

可以將解析數(shù)獨的整個過程分成3步:

第一步:從圖像中提取數(shù)獨

第二步:提取圖像中出現(xiàn)的每個數(shù)字

第三步:用算法計算數(shù)獨的解

第一步:從圖像中提取數(shù)獨

首先需要進行圖像處理。

1、對圖像進行預處理

首先,我們應用高斯模糊的內(nèi)核大小(高度,寬度)為9的圖像。注意,內(nèi)核大小必須是正的和奇數(shù)的,并且內(nèi)核必須是平方的。然后使用11個最近鄰像素自適應閾值。

proc=cv2.GaussianBlur(img.copy(),(9,9),0)proc=cv2.adaptiveThreshold(proc,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)

為了使網(wǎng)格線具有非零像素值,我們顛倒顏色。此外,把圖像放大,以增加網(wǎng)格線的大小。

proc=cv2.bitwise_not(proc,proc)kernel=np.array([[0。,1.,0.],[1.,1.,1.],[0.,1.,0.]],np.uint8)proc=cv2.dilate(proc,kernel)

閾值化后的數(shù)獨圖像

2、找出多邊形的角

下一步是尋找圖像中輪廓的4個角。所以需要找到所有的輪廓線,按面積降序排序,然后選擇面積的那個。

_,contours,h=cv2.findContours(img.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)contours=sorted(contours,key=cv2.contourArea,reverse=True)polygon=contours[0]

使用的操作符。帶有max和min的itemgetter允許我們獲得該點的索引。每個點都是有1個坐標的數(shù)組,然后[0]和[1]分別用于獲取x和y。

右下角點具有的(x + y)值;左上角有點最小(x + y)值;左下角則具有最小的(x - y)值;右上角則具有的(x - y)值。

bottom_right,_=max(enumerate([pt[0][0]+pt[0][1]forptinpolygon]),key=operator.itemgetter(1))top_left,_=min(enumerate([pt[0][0]+pt[0][1]forptinpolygon]),key=operator.itemgetter(1))bottom_left,_=min(enumerate([pt[0][0]-pt[0][1]forptinpolygon]),key=operator.itemgetter(1))top_right,_=max(enumerate([pt[0][0]-pt[0][1]forptinpolygon]),key=operator.itemgetter(1))

現(xiàn)在我們有了4個點的坐標,然后需要使用索引返回4個點的數(shù)組。每個點都在自己的一個坐標數(shù)組中。

[polygon[top_left][0],polygon[top_right][0],polygon[bottom_right][0],polygon[bottom_left][0]]

多邊形的四個角

3、裁剪和變形圖像

有了數(shù)獨的4個坐標后,我們需要剪裁和彎曲一個矩形部分,從一個圖像變成一個類似大小的正方形。由左上、右上、右下和左下點描述的矩形。

注意:將數(shù)據(jù)類型顯式設置為float32或‘getPerspectiveTransform’會引發(fā)錯誤。

top_left,top_right,bottom_right,bottom_left=crop_rect[0],crop_rect[1],crop_rect[2],crop_rect[3]src=np.array([top_left,top_right,bottom_right,bottom_left],dtype=float32)side=max([distance_between(bottom_right,top_right),distance_between(top_left,bottom_left),distance_between(bottom_right,bottom_left),distance_between(top_left,top_right)])

用計算長度的邊來描述一個正方形,這是要轉(zhuǎn)向的新視角。然后要做的是通過比較之前和之后的4個點來得到用于傾斜圖像的變換矩陣。最后,再對原始圖像進行變換。

dst=np.array([[0,0],[side-1,0],[side-1,side-1],[0,side-1]],dtype=float32)m=cv2.getPerspectiveTransform(src,dst)cv2.warpPerspective(img,m,(int(side),int(side)))

裁剪和變形后的數(shù)獨圖像

4、從正方形圖像中推斷網(wǎng)格

從正方形圖像推斷出81個單元格。我們在這里交換 j 和 i ,這樣矩形就被存儲在從左到右讀取的列表中,而不是自上而下。

squares=[]side=img.shape[:1]sideside=side[0]/9forjinrange(9):foriinrange(9):p1=(i*side,j*side)#Topleftcornerofaboxp2=((i+1)*side,(j+1)*side)#Bottomrightcornersquares.append((p1,p2))returnsquares

5、得到每一位數(shù)字

下一步是從其單元格中提取數(shù)字并構(gòu)建一個數(shù)組。

digits=[]img=pre_process_image(img.copy(),skip_dilate=True)forsquareinsquares:digits.append(extract_digit(img,square,size))

extract_digit 是從一個數(shù)獨方塊中提取一個數(shù)字(如果有的話)的函數(shù)。它從整個方框中得到數(shù)字框,使用填充特征查找來獲得框中間的特征,以期在邊緣找到一個屬于該數(shù)字的像素,用于定義中間的區(qū)域。接下來,需要縮放并填充數(shù)字,讓適合用于機器學習的數(shù)字大小的平方。同時,我們必須忽略任何小的邊框。

defextract_digit(img,rect,size):digit=cut_from_rect(img,rect)h,w=digit.shape[:2]margin=int(np.mean([h,w])/2.5)_,bbox,seed=find_largest_feature(digit,[margin,margin],[w-margin,h-margin])digit=cut_from_rect(digit,bbox)w=bbox[1][0]-bbox[0][0]h=bbox[1][1]-bbox[0][1]ifw>0andh>0and(w*h)>100andlen(digit)>0:returnscale_and_centre(digit,size,4)else:returnnp.zeros((size,size),np.uint8)

最后的數(shù)獨的形象

現(xiàn)在,我們有了最終的數(shù)獨預處理圖像,下一個任務是提取圖像中的每一位數(shù)字,并將其存儲在一個矩陣中,然后通過某種算法計算出數(shù)獨的解。

第二步:提取圖像中出現(xiàn)的每個數(shù)字

對于數(shù)字識別,我們將在MNIST數(shù)據(jù)集上訓練神經(jīng)網(wǎng)絡,該數(shù)據(jù)集包含60000張0到9的數(shù)字圖像。從導入所有庫開始。

importnumpyimportcv2fromkeras.datasetsimportmnistfromkeras.modelsimportSequentialfromkeras.layersimportDensefromkeras.layersimportDropoutfromkeras.layersimportFlattenfromkeras.layers.convolutionalimportConv2Dfromkeras.layers.convolutionalimportMaxPooling2Dfromkeras.utilsimportnp_utilsfromkerasimportbackendasKimportmatplotlib.pyplotasplt

需要修復隨機種子以確??芍貜托?。

K.set_image_dim_ordering(th)seed=7numpy.random.seed(seed)(X_train,y_train),(X_test,y_test)=mnist.load_data()

然后將圖像重塑為樣本*像素*寬度*高度,并輸入從0-255規(guī)范化為0-1。在此之后,對輸出進行熱編碼。

X_trainX_train=X_train.reshape(X_train.shape[0],1,28,28).astype(float32)X_testX_test=X_test.reshape(X_test.shape[0],1,28,28).astype(float32)X_trainX_train=X_train/255X_testX_test=X_test/255y_train=np_utils.to_categorical(y_train)y_test=np_utils.to_categorical(y_test)num_classes=y_test.shape[1]

接下來,我們將創(chuàng)建一個模型來預測手寫數(shù)字。

model=Sequential()model.add(Conv2D(32,(5,5),input_shape=(1,28,28),activation=relu))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Conv2D(16,(3,3),activation=relu))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Dropout(0.2))model.add(Flatten())model.add(Dense(128,activation=relu))model.add(Dense(64,activation=relu))model.add(Dense(num_classes,activation=softmax))

模型總結(jié)

在創(chuàng)建模型之后,需要進行編譯,使其適合數(shù)據(jù)集并對其進行評估。

model.compile(loss=categorical_crossentropy,optimizer=adam,metrics=[accuracy])model.fit(X_train,y_train,validation_data=(X_test,y_test),epochs=10,batch_size=200)scores=model.evaluate(X_test,y_test,verbose=0)print(LargeCNNError:%.2f%%%(100-scores[1]*100))

現(xiàn)在,可以測試上面創(chuàng)建的模型了。

test_images=X_test[1:5]test_imagestest_images=test_images.reshape(test_images.shape[0],28,28)print(Testimagesshape:{}.format(test_images.shape))fori,test_imageinenumerate(test_images,start=1):org_image=test_imagetest_imagetest_image=test_image.reshape(1,1,28,28)prediction=model.predict_classes(test_image,verbose=0)print(Predicteddigit:{}.format(prediction[0]))plt.subplot(220+i)plt.axis(off)plt.title(Predicteddigit:{}.format(prediction[0]))plt.imshow(org_image,cmap=plt.get_cmap(gray))plt.show()

手寫體數(shù)字分類模型的預測數(shù)字

神經(jīng)網(wǎng)絡的精度為98.314%!最后,保存序列模型,這樣就不必在需要使用它的時候反復訓練了。

#serializemodeltoJSONmodelmodel_json=model.to_json()withopen(model.json,w)asjson_file:json_file.write(model_json)#serializeweightstoHDF5model.save_weights(model.h5)print(Savedmodeltodisk)

更多關(guān)于手寫數(shù)字識別的信息:

https://github.com/aakashjhawar/Handwritten-Digit-Recognition

下一步是加載預先訓練好的模型。

json_file=open(model.json,r)loaded_model_json=json_file.read()json_file.close()loaded_model=model_from_json(loaded_model_json)loaded_model.load_weights(model.h5)

調(diào)整圖像大小,并將圖像分割成9x9的小圖像。每個小圖像的數(shù)字都是從1-9。

sudoku=cv2.resize(sudoku,(450,450))grid=np.zeros([9,9])foriinrange(9):forjinrange(9):image=sudoku[i*50:(i+1)*50,j*50:(j+1)*50]ifimage.sum()>25000:grid[i][j]=identify_number(image)else:grid[i][j]=0gridgrid=grid.astype(int)

identify_number 函數(shù)拍攝數(shù)字圖像并預測圖像中的數(shù)字。

defidentify_number(image):image_resize=cv2.resize(image,(28,28))#Forplt.imshowimage_resizeimage_resize_2=image_resize.reshape(1,1,28,28)#Forinputtomodel.predict_classes#cv2.imshow(number,image_test_1)loaded_modelloaded_model_pred=loaded_model.predict_classes(image_resize_2,verbose=0)returnloaded_model_pred[0]

完成以上步驟后,數(shù)獨網(wǎng)格看起來是這樣的:

提取的數(shù)獨

第三步:用回溯算法計算數(shù)獨的解

我們將使用回溯算法來計算數(shù)獨的解。

在網(wǎng)格中搜索仍未分配的條目。如果找到引用參數(shù)行,col 將被設置為未分配的位置,而 true 將被返回。如果沒有未分配的條目保留,則返回false。“l” 是 solve_sudoku 函數(shù)傳遞的列表變量,用于跟蹤行和列的遞增。

deffind_empty_location(arr,l):forrowinrange(9):forcolinrange(9):if(arr[row][col]==0):l[0]=rowl[1]=colreturnTruereturnFalse

返回一個boolean,指示指定行的任何賦值項是否與給定數(shù)字匹配。

defused_in_row(arr,row,num):foriinrange(9):if(arr[row][i]==num):returnTruereturnFalse

返回一個boolean,指示指定列中的任何賦值項是否與給定數(shù)字匹配。

defused_in_col(arr,col,num):foriinrange(9):if(arr[i][col]==num):returnTruereturnFalse

返回一個boolean,指示指定的3x3框內(nèi)的任何賦值項是否與給定的數(shù)字匹配。

defused_in_box(arr,row,col,num):foriinrange(3):forjinrange(3):if(arr[i+row][j+col]==num):returnTruereturnFalse

檢查將num分配給給定的(row, col)是否合法。檢查“ num”是否尚未放置在當前行,當前列和當前3x3框中。

defcheck_location_is_safe(arr,row,col,num):returnnotused_in_row(arr,row,num)andnotused_in_col(arr,col,num)andnotused_in_box(arr,row-row%3,col-col%3,num)

采用部分填入的網(wǎng)格,并嘗試為所有未分配的位置分配值,以滿足數(shù)獨解決方案的要求(跨行、列和框的非重復)。“l” 是一個列表變量,在 find_empty_location 函數(shù)中保存行和列的記錄。將我們從上面的函數(shù)中得到的行和列賦值給列表值。

defsolve_sudoku(arr):l=[0,0]if(notfind_empty_location(arr,l)):returnTruerow=l[0]col=l[1]fornuminrange(1,10):if(check_location_is_safe(arr,row,col,num)):arr[row][col]=numif(solve_sudoku(arr)):returnTrue#failure,unmake&tryagainarr[row][col]=0returnFalse

最后一件事是print the grid。

defprint_grid(arr):foriinrange(9):forjinrange(9):print(arr[i][j])print()

最后,把所有的函數(shù)整合在主函數(shù)中。

defsudoku_solver(grid):if(solve_sudoku(grid)):print(---)else:print(Nosolutionexists)gridgrid=grid.astype(int)returngrid

這個函數(shù)的輸出將是最終解出的數(shù)獨。

最終的解決方案

當然,這個解決方案絕不是萬無一失的,處理圖像時仍然會出現(xiàn)一些問題,要么無法解析,要么解析錯誤導致無法處理。不過,我們的目標是探索新技術(shù),從這個角度來看,這個項目還是有價值的。

網(wǎng)頁題目:干貨|手把手教你用115行代碼做個數(shù)獨解析器!
轉(zhuǎn)載注明:http://jinyejixie.com/article42/cjohec.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供電子商務響應式網(wǎng)站、網(wǎng)站排名網(wǎng)站維護、品牌網(wǎng)站建設、移動網(wǎng)站建設

廣告

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

成都定制網(wǎng)站網(wǎng)頁設計
伽师县| 高清| 越西县| 长兴县| 嫩江县| 玛沁县| 桂平市| 土默特左旗| 建始县| 大冶市| 五大连池市| 阜康市| 阿巴嘎旗| 灵台县| 佛山市| 黄骅市| 马尔康县| 时尚| 灵山县| 石渠县| 三都| 海盐县| 景德镇市| 梁河县| 潼关县| 祁连县| 碌曲县| 措美县| 甘肃省| 湟源县| 攀枝花市| 水富县| 淮滨县| 宁乡县| 增城市| 鹤壁市| 隆回县| 蒙城县| 吴江市| 拉萨市| 阳谷县|