def build_perspective_move_map(row, col, ratio_col_t, ratio_row, ratio_col_d): ''' # row:高度 # col:寬度 # ratio_col_t:上邊縮小的比率,可以用0.85 # ratio_row :高度縮小的比率,可以用0.95 # ratio_col_d:下邊縮小的比率,可以用0.95 ''' ### 注意這邊(0,0)是用圖的中心當原點,不是圖的左上角喔! x, y = get_xy_map(row, col) x = x - int(col / 2) y = y - int(row / 2) persp_row = row * ratio_row / 2 ### 下方 y方向的縮小比率 persp_y = y * ratio_row ### 下方 透射後的y座標 ratio_col = ratio_col_t * (persp_row - persp_y) / (persp_row * 2) + \ ratio_col_d * (persp_y - (-int(row / 2) * ratio_row)) / (persp_row * 2) ### x方向的縮小比率,這事會隨y而變化的,看筆記的圖才好理解喔! persp_x = x * ratio_col ### 透射後的x座標 move_x = persp_x - x ### 原x座標怎麼位移到透射 move_y = persp_y - y ### 原y座標怎麼位移到透射 move_map = np.dstack( (move_x, move_y)) ### 我move_map個格式就是shape=(row, col, 2),所以拼起來一下囉! return move_map
def apply_move_to_rec_tf(dis_img, move_map, max_db_move_x, max_db_move_y): max_db_move_x = tf.convert_to_tensor(max_db_move_x, dtype=tf.float32) max_db_move_y = tf.convert_to_tensor(max_db_move_y, dtype=tf.float32) # move_map = tf.convert_to_tensor(move_map,dtype=tf.float32) row, col = move_map.shape[:2] ### 256, 256 go_x, go_y = get_xy_map(row, col) ### 注意,無法用 move_map[...,0]=... 的寫法,好像是 不能 單格指定值給 tensor裡的元素, 只能 整個tensor一起給值, # 所以才分成下三行 造出 整體要操作的tensor 再一起操作喔! x_move = move_map[..., 0] + go_x + max_db_move_x y_move = move_map[..., 1] + go_y + max_db_move_y xy_move = tf.stack((x_move, y_move), axis=2) move_map += xy_move ### 整包加進去~ move_map = tf.cast(move_map, tf.int32) ### tensor沒有辦法 像numpy 一樣靈活 用 array[ [1,3,5,...] ] 這種用法,所以要用 tf.numpy_function,把tensor轉成 numpy處理囉! rec_img = tf.numpy_function(fun, [dis_img, move_map], tf.float32) # print(type(dis_img),dis_img.dtype) # print(type(move_map),move_map.dtype) # print(type(max_db_move_x),max_db_move_x.dtype) # print(type(max_db_move_y),max_db_move_y.dtype) # print(type(dis_img),dis_img.dtype) # print(type(move_map),move_map.dtype) # print(type(row)) # print(type(col)) # print(type(go_x),go_x.dtype) # print(type(go_y),go_y.dtype) # print(type(x_move),y_move.dtype) # print(type(y_move),y_move.dtype) return rec_img
def build_page_move_x(row, col, lr_shift=5): width = col height = row x, y = get_xy_map(row, col) ### 公式推倒過程看筆記 m = (-lr_shift - lr_shift) / width z = m * x + lr_shift return z
def apply_move_to_rec2(dis_img, move_map, max_db_move_x, max_db_move_y): # start_time = time.time() dis_row, dis_col = dis_img.shape[:2] ### 原始的 5xx, 5xx,不是512, 512喔! row, col = move_map.shape[:2] ### 256, 256 rec_img = np.zeros(shape=(row, col, 3), dtype=np.uint8) ### 建立存恢復影像的畫布,256,256 go_x, go_y = get_xy_map(row, col) proc_move_map = move_map.copy() proc_move_map[..., 0] += go_x + max_db_move_x proc_move_map[..., 1] += go_y + max_db_move_y proc_move_map = proc_move_map.astype(np.int32) over_bound_msk = np.zeros(shape=(row, col), dtype=np.uint8) ### 用一個mask紀錄哪些pixel超出邊界 over_bound_msk[ proc_move_map[..., 0] >= dis_col] = 1 ### 只需=1即可,覺得不需要+=1,因為不需要 區分 x超過、y超過 還是 xy都超過,只要超過就算超過 over_bound_msk[proc_move_map[..., 0] < dis_col * -1] = 1 over_bound_msk[proc_move_map[..., 1] >= dis_row] = 1 over_bound_msk[proc_move_map[..., 1] < dis_col * -1] = 1 ### 修整move_map proc_move_map[proc_move_map[..., 0] >= dis_col, 0] = dis_col - 1 ### 太大超出邊界,設定成邊界 proc_move_map[proc_move_map[..., 1] >= dis_row, 1] = dis_row - 1 ### 太大超出邊界,設定成邊界 proc_move_map[proc_move_map[..., 0] < dis_col * -1, 0] = 0 ### 太小超出篇界,設定成0 proc_move_map[proc_move_map[..., 1] < dis_col * -1, 1] = 0 ### 太小超出篇界,設定成0 # np.save("proc_move_map_clip",proc_move_map) # cv2.imwrite("dis_img.bmp",dis_img) rec_img = dis_img[proc_move_map[..., 1], proc_move_map[..., 0], :] ### 用修整後的move_map回復影像 ### 如果 move_map 本身的值已經爆掉了,那rec_img的該點就填0~ 這樣做沒問題!注意我現在是用 move_map 回去 dis_img找顏色填回來, # 所以 rec_img的每個pixel 只有一個相應的 move_map pixel, # 代表rec_img的每個pixel只會有一個來源,不會同時有 兩個來源, # 所以不會有一個合法一個不合法,然後不合法蓋過原本合法值的問題! rec_img[over_bound_msk == 1] = 0 ### predict出的move_map超出邊界的pixel設0 # rec_img[ proc_move_map[...,0]<0 ] = 0 # rec_img[ proc_move_map[...,0]>dis_col ] = 0 # rec_img[ proc_move_map[...,1]<0 ] = 0 # rec_img[ proc_move_map[...,1]>dis_row ] = 0 # print("cost time:",time.time()-start_time) return rec_img
def build_page_move_y(row, col, top_curl=27, down_curl=19): width = col height = row x, y = get_xy_map(row, col) ### 公式推倒過程看筆記 A = (-down_curl - top_curl) / (height * (width / 2)**2) m = A * (x - (width / 2))**2 B = (top_curl - 0) * 4 / ( width**2 ) ### 原本27-6,但覺得-0也可以,覺得原本-6應該是因為 拍照的誤差造成的 最小移動量要往上跑6,所以不要應該也是可以 b = B * ( (x - (width / 2))**2 ) + 0 ### 原本 +6,但覺得+0也可以,覺得原本+6應該是因為 拍照的誤差造成的 最小移動量要往上跑6,所以不要應該也是可以 z = m * y + b return z
def apply_move_to_rec2(dis_img, move_map, max_db_move_x, max_db_move_y): dis_row, dis_col = dis_img.shape[:2] ### 原始的 5xx, 5xx,不是5125, 512喔! row, col = move_map.shape[:2] ### 256, 256 rec_img = np.zeros(shape=(row, col, 3), dtype=np.uint8) ### 建立存恢復影像的畫布,256,256 go_x, go_y = get_xy_map(row, col) move_map2 = move_map.copy() move_map2[..., 0] += go_x + max_db_move_x move_map2[..., 1] += go_y + max_db_move_y move_map2 = move_map2.astype(np.int32) ### 比較最核心的這一步,不用numba 花多少時間: ### 不用numba:10000 花8秒 start_time = time.time() for i in range(10000): rec_img = dis_img[move_map2[..., 1], move_map2[..., 0], :] print("cost time:", time.time() - start_time) ### 用numba:10000 花79秒 start_time = time.time() W = col H = row threadsperblock = (32, 32) blockspergrid_x = math.ceil(W / threadsperblock[0]) blockspergrid_y = math.ceil(H / threadsperblock[1]) blockspergrid = (blockspergrid_x, blockspergrid_y) for i in range(10000): kong[blockspergrid, threadsperblock](dis_img.astype(np.int32), move_map2, rec_img.astype(np.int32)) print("cost time:", time.time() - start_time) ### 如果 move_map 本身的值已經爆掉了,那rec_img的該點就填0~ 這樣做沒問題!注意我現在是用 move_map 回去 dis_img找顏色填回來, # 所以 rec_img的每個pixel 只有一個相應的 move_map pixel, # 代表rec_img的每個pixel只會有一個來源,不會同時有 兩個來源, # 所以不會有一個合法一個不合法,然後不合法蓋過原本合法值的問題! # rec_img[ move_map2[...,0]<0 ] = 0 # rec_img[ move_map2[...,0]>dis_col ] = 0 # rec_img[ move_map2[...,1]<0 ] = 0 # rec_img[ move_map2[...,1]>dis_row ] = 0 return rec_img
def build_perspective_move_y(row, col): width = col height = row x, y = get_xy_map(row, col) # 寫出係數矩陣 A A = np.array([[25**4, 25**3, 25**2, 25**1], [50**4, 50**3, 50**2, 50**1], [100**4, 100**3, 100**2, 100**1], [360**4, 360**3, 360**2, 360**1]]) # 寫出常數矩陣 B B = np.array([-8, 0, 13, -30]).reshape(4, 1) # 找出係數矩陣的反矩陣 A_inv A_inv = np.linalg.inv(A) # 將 A_inv 與 B 相乘,即可得到解答 ans = A_inv.dot(B) print("ans", ans) ### 公式推倒過程看筆記 a = ans[0] #-0.0000604 b = ans[1] #0.2336 c = ans[2] #-0.864 d = ans[3] z = a * y**4 + b * y**3 + c * y**2 + d * y**1 return z
valinit=1, valstep=0.01) ratio_row_sl = Slider(ratio_row_ax, 'ratio_row', 0, 1, valinit=1, valstep=0.01) ratio_col_d_sl = Slider(ratio_col_d_ax, 'ratio_col_d', 0, 1, valinit=1, valstep=0.01) top_curl_sl = Slider(top_curl_ax, 'top_curl', 0, 100, valinit=0, valstep=1) down_curl_sl = Slider(down_curl_ax, 'down_curl', 0, 100, valinit=0, valstep=1) lr_shift_sl = Slider(lr_shift_ax, 'lr_shift', 0, 100, valinit=0, valstep=1) ### 3.Slide功能 ### 初始化 一些 等等要用到的東西 x, y = get_xy_map(int(row), int(col)) ### 從 0~row 或 0~col xy_map = np.dstack((x, y)) ax_img = ax.scatter(x, y) ax = ax.invert_yaxis() # ax_img = ax.scatter(xy_map[:,0], xy_map[:,1], c = np.arange(row*col), cmap="brg") ### 有漸層顏色,但是很慢所以註解掉了 ### 定義 滑動bar時要做的事情 def apply_move(): global row, col, top_curl, down_curl, lr_shift, ratio_col_t, ratio_row, ratio_col_d, dis_type ratio_col_t = ratio_col_t_sl.val ratio_row = ratio_row_sl.val ratio_col_d = ratio_col_d_sl.val top_curl = top_curl_sl.val down_curl = down_curl_sl.val