成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

人工智能 機器學習
這里有一份數獨解析教程,等待你查收~ 喜歡收藏硬核干貨的小伙伴看過來。

 

你也是數獨愛好者嗎?

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

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

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

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

第一步:從圖像中提取數獨

第二步:提取圖像中出現的每個數字

第三步:用算法計算數獨的解

第一步:從圖像中提取數獨

首先需要進行圖像處理。

1、對圖像進行預處理

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

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

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

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

       

閾值化后的數獨圖像

2、找出最大多邊形的角

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

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

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

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

  1. bottom_right, _ = max(enumerate([pt[0][0] + pt[0][1] for pt in  
  2.                       polygon]), key=operator.itemgetter(1))  
  3. top_left, _ = min(enumerate([pt[0][0] + pt[0][1] for pt in  
  4.                   polygon]), key=operator.itemgetter(1))  
  5. bottom_left, _ = min(enumerate([pt[0][0] - pt[0][1] for pt in  
  6.                      polygon]), key=operator.itemgetter(1))  
  7. top_right, _ = max(enumerate([pt[0][0] - pt[0][1] for pt in  
  8.                    polygon]), key=operator.itemgetter(1)) 

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

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

最大多邊形的四個角

3、裁剪和變形圖像

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

注意:將數據類型顯式設置為float32或‘getPerspectiveTransform’會引發錯誤。 

  1. top_left, top_right, bottom_right, bottom_left = crop_rect[0], crop_rect[1], crop_rect[2], crop_rect[3]  
  2. src = np.array([top_left, top_right, bottom_right, bottom_left], dtypefloat32 )   
  3. side = max([  distance_between(bottom_right, top_right),   
  4.             distance_between(top_left, bottom_left),  
  5.             distance_between(bottom_right, bottom_left),     
  6.             distance_between(top_left, top_right) ]) 

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

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

裁剪和變形后的數獨圖像

4、從正方形圖像中推斷網格

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

  1. squares = []   
  2. side = img.shape[:1]   
  3. sideside = side[0] / 9 
  4. for j in range(9):  
  5.     for i in range(9):  
  6.         p1 = (i * side, j * side)  #Top left corner of a box    
  7.         p2 = ((i + 1) * side, (j + 1) * side)  #Bottom right corner       
  8.          squares.append((p1, p2)) return squares 

5、得到每一位數字

下一步是從其單元格中提取數字并構建一個數組。 

  1. digits = []  
  2. img = pre_process_image(img.copy(), skip_dilate=True 
  3. for square in squares:  
  4.     digits.append(extract_digit(img, square, size)) 

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

  1. def extract_digit(img, rect, size):  
  2.     digit = cut_from_rect(img, rect)  
  3.     h, w = digit.shape[:2]  
  4.     margin = int(np.mean([h, w]) / 2.5)  
  5.     _, bbox, seed = find_largest_feature(digit, [margin, margin], [w  
  6.     - margin, h - margin])  
  7.     digit = cut_from_rect(digit, bbox)   
  8.     w = bbox[1][0] - bbox[0][0]  
  9.     h = bbox[1][1] - bbox[0][1]  
  10.     if w > 0 and h > 0 and (w * h) > 100 and len(digit) > 0:  
  11.         return scale_and_centre(digit, size, 4)  
  12.     else:  
  13.         return np.zeros((size, size), np.uint8) 

      

最后的數獨的形象

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

第二步:提取圖像中出現的每個數字

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

  1. import numpy  
  2. import cv2from keras.datasets   
  3. import mnistfrom keras.models   
  4. import Sequentialfrom keras.layers   
  5. import Densefrom keras.layers   
  6. import Dropoutfrom keras.layers   
  7. import Flattenfrom keras.layers.convolutional   
  8. import Conv2Dfrom keras.layers.convolutional   
  9. import MaxPooling2Dfrom keras.utils   
  10. import np_utilsfrom keras   
  11. import backend as K  
  12. import matplotlib.pyplot as plt 

需要修復隨機種子以確保可重復性。 

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

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

  1. X_trainX_train = X_train.reshape(X_train.shape[0], 1, 28,  
  2.                            28).astype( float32 )  
  3. X_testX_test = X_test.reshape(X_test.shape[0], 1, 28,  
  4.                            28).astype( float32 )   
  5. X_trainX_train = X_train / 255  
  6. X_testX_test = X_test / 255 
  7. y_train = np_utils.to_categorical(y_train)  
  8. y_test = np_utils.to_categorical(y_test)  
  9. num_classes = y_test.shape[1] 

接下來,我們將創建一個模型來預測手寫數字。 

  1. model = Sequential()  
  2. model.add(Conv2D(32, (5, 5), input_shape=(1, 28, 28),  
  3.           activationrelu ))  
  4. model.add(MaxPooling2D(pool_size=(2, 2)))model.add(Conv2D(16, (3,  
  5.           3), activationrelu ))  
  6. model.add(MaxPooling2D(pool_size=(2, 2))) 
  7. model.add(Dropout(0.2)) 
  8. model.add(Flatten())  
  9. model.add(Dense(128, activationrelu ))  
  10. model.add(Dense(64, activationrelu ))  
  11. model.add(Dense(num_classes, activationsoftmax )) 

模型總結

在創建模型之后,需要進行編譯,使其適合數據集并對其進行評估。 

  1. model.compile(losscategorical_crossentropy , optimizeradam ,  
  2.                metrics=[ accuracy ])  
  3. model.fit(X_train, y_train, validation_data=(X_test, y_test),  
  4.                epochs=10batch_size=200 
  5. scores = model.evaluate(X_test, y_test, verbose=0 
  6. print("Large CNN Error: %.2f%%" % (100-scores[1]*100)) 

現在,可以測試上面創建的模型了。 

  1. test_images = X_test[1:5]  
  2. test_imagestest_images = test_images.reshape(test_images.shape[0], 28, 28)  
  3. print ("Test images shape: {}".format(test_images.shape))  
  4. for i, test_image in enumerate(test_images, start=1):  
  5.     org_image = test_image  
  6.     test_imagetest_image = test_image.reshape(1,1,28,28)  
  7.     prediction = model.predict_classes(test_image, verbose=0 
  8.     print ("Predicted digit: {}".format(prediction[0]))  
  9.     plt.subplot(220+i)  
  10.     plt.axis( off )  
  11.     plt.title("Predicted digit: {}".format(prediction[0]))  
  12.     plt.imshow(org_image, cmap=plt.get_cmap( gray ))  
  13. plt.show() 

手寫體數字分類模型的預測數字

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

  1. # serialize model to JSON  
  2. modelmodel_json = model.to_json()  
  3. with open("model.json", "w") as json_file:  
  4.     json_file.write(model_json) 
  5. # serialize weights to HDF5  
  6. model.save_weights("model.h5")  
  7. print("Saved model to disk") 

更多關于手寫數字識別的信息:

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

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

  1. json_file = open( model.json ,  r )  
  2. loaded_model_json = json_file.read()  
  3. json_file.close()  
  4. loaded_model = model_from_json(loaded_model_json)  
  5. loaded_model.load_weights("model.h5") 

調整圖像大小,并將圖像分割成9x9的小圖像。每個小圖像的數字都是從1-9。 

  1. sudoku = cv2.resize(sudoku, (450,450))  
  2. grid = np.zeros([9,9])  
  3. for i in range(9):  
  4.     for j in range(9):  
  5.         image = sudoku[i*50:(i+1)*50,j*50:(j+1)*50]  
  6.         if image.sum() > 25000:      
  7.             grid[i][j] = identify_number(image)  
  8.         else:  
  9.             grid[i][j] = 0      
  10. gridgrid =  grid.astype(int) 

identify_number 函數拍攝數字圖像并預測圖像中的數字。 

  1. def identify_number(image):  
  2.     image_resize = cv2.resize(image, (28,28))    # For plt.imshow  
  3.     image_resizeimage_resize_2 = image_resize.reshape(1,1,28,28)    # For input to model.predict_classes  
  4. #    cv2.imshow( number , image_test_1)  
  5.     loaded_modelloaded_model_pred = loaded_model.predict_classes(image_resize_2   
  6.                                                       , verbose = 0 
  7.     return loaded_model_pred[0]  

完成以上步驟后,數獨網格看起來是這樣的:

提取的數獨

第三步:用回溯算法計算數獨的解

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

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

  1. def find_empty_location(arr,l):  
  2.     for row in range(9):  
  3.         for col in range(9):  
  4.             if(arr[row][col]==0):  
  5.                 l[0]=row  
  6.                 l[1]=col  
  7.                 return True  
  8.     return False 

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

  1. def used_in_row(arr,row,num):  
  2.     for i in range(9):     
  3.         if(arr[row][i] == num):    
  4.             return True  
  5.     return False 

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

  1. def used_in_col(arr,col,num):  
  2.     for i in range(9):    
  3.         if(arr[i][col] == num):   
  4.             return True  
  5.     return False 

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

  1. def used_in_box(arr,row,col,num):  
  2.     for i in range(3):  
  3.         for j in range(3):  
  4.             if(arr[i+row][j+col] == num):      
  5.             return True  
  6.      return False 

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

  1. def check_location_is_safe(arr,row,col,num):  
  2.     return not used_in_row(arr,row,num) and   
  3.            not used_in_col(arr,col,num) and   
  4.            not used_in_box(arr,row - row%3,col - col%3,num) 

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

  1. def solve_sudoku(arr):  
  2.     l=[0,0]   
  3.     if(not find_empty_location(arr,l)):  
  4.         return True   
  5.     row=l[0]  
  6.     col=l[1]   
  7.     for num in range(1,10):   
  8.         if(check_location_is_safe(arr,row,col,num)):   
  9.             arr[row][col]=num   
  10.             if(solve_sudoku(arr)):   
  11.                 return True   
  12.             # failure, unmake & try again   
  13.             arr[row][col] = 0   
  14.     return False 

最后一件事是print the grid。 

  1. def print_grid(arr):  
  2.     for i in range(9):  
  3.         for j in range(9):    
  4.             print (arr[i][j])   
  5.          print (  ) 

最后,把所有的函數整合在主函數中。 

  1. def sudoku_solver(grid):  
  2.     if(solve_sudoku(grid)):  
  3.         print( --- )  
  4.     else:  
  5.         print ("No solution exists")  
  6.     gridgrid = grid.astype(int) 
  7.      return grid 

這個函數的輸出將是最終解出的數獨。

最終的解決方案

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

 

責任編輯:龐桂玉 來源: 機器學習算法與Python學習
相關推薦

2017-10-29 21:43:25

人臉識別

2022-10-19 14:30:59

2017-10-27 10:29:35

人臉識別UbuntuPython

2021-08-09 13:31:25

PythonExcel代碼

2022-08-04 10:39:23

Jenkins集成CD

2011-03-28 16:14:38

jQuery

2021-02-06 14:55:05

大數據pandas數據分析

2021-02-04 09:00:57

SQLDjango原生

2020-08-12 07:41:39

SQL 優化語句

2022-06-30 16:10:26

Python計時器裝飾器

2009-04-22 09:17:19

LINQSQL基礎

2012-01-11 13:40:35

移動應用云服務

2021-08-02 23:15:20

Pandas數據采集

2020-03-08 22:06:16

Python數據IP

2021-12-11 20:20:19

Python算法線性

2021-02-02 13:31:35

Pycharm系統技巧Python

2021-05-10 06:48:11

Python騰訊招聘

2021-01-21 09:10:29

ECharts柱狀圖大數據

2021-01-08 10:32:24

Charts折線圖數據可視化

2022-05-11 10:45:21

SpringMVC框架Map
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美在线高清 | 日韩欧美精品一区 | 精品国产99 | 亚洲高清在线 | 一级女毛片 | 99精品视频一区二区三区 | 黄网站免费在线观看 | 精品久久久久久久久久 | 久久久精品视频一区二区三区 | 懂色一区二区三区免费观看 | 激情六月丁香婷婷 | 女女爱爱视频 | 免费黄色的视频 | 一区二区三区视频免费观看 | 久久国产成人 | 国产片网站 | 国产精品一区二区三级 | 成人在线中文字幕 | 国产精品视频一区二区三 | 美女网站视频免费黄 | 久久精品在线播放 | 在线看片网站 | 成人免费观看男女羞羞视频 | 成人不卡一区二区 | 毛片网站在线观看视频 | 亚洲欧美综合网 | 国产一区二 | 久久久久久国产精品 | 日韩一区中文字幕 | 国产成人小视频 | 国产精品久久亚洲 | 青娱乐av | 午夜影院普通用户体验区 | 做a网站 | www.av7788.com | 国产98色在线 | av一级| 国产一区成人 | 国产免费福利 | 午夜电影在线播放 | 无码日韩精品一区二区免费 |