pylineament 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pylineament might be problematic. Click here for more details.

@@ -0,0 +1,766 @@
1
+ import sys
2
+ import numpy as np
3
+ import pyqtgraph as pg
4
+ from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
5
+ QPushButton, QFileDialog,
6
+ QTabWidget, QTextEdit,
7
+ QHBoxLayout, QSlider, QLabel,
8
+ QSpacerItem, QSizePolicy, QComboBox,
9
+ QLineEdit, QCheckBox, QGridLayout, QProgressBar, QSplitter )
10
+
11
+ from PyQt5.QtCore import QThreadPool, QRunnable, pyqtSignal, QObject
12
+
13
+
14
+ from skimage.transform import rescale
15
+ from PyQt5.QtCore import Qt
16
+ import numpy as np
17
+ import pandas as pd
18
+ from pylineament import (dem_to_line, read_raster,
19
+ extract_lineament_points,
20
+ convert_points_to_line,
21
+ dem_to_line_runner,
22
+ dem_to_line_runner_small,
23
+ reduce_lines,
24
+ image_splitting,
25
+ merge_lines_csv_to_shp,
26
+ merge_single_csv_to_shp,
27
+ hillshade)
28
+ import os
29
+
30
+
31
+
32
+ class ImageSplitterParallel(QRunnable):
33
+ def __init__(self, i, crs, im, transform ,temp_folder):
34
+ super().__init__()
35
+
36
+ self.i = i
37
+
38
+ self.n_ = i
39
+ self.crs = crs
40
+ self.im = im
41
+ self.transform = transform
42
+ self.temp_folder = temp_folder
43
+
44
+
45
+ def run(self):
46
+ import rasterio
47
+ import os
48
+
49
+ n_ = str(self.n_ ).zfill(5) +'.tiff'
50
+
51
+ Z = self.im
52
+
53
+ new_dataset = rasterio.open(
54
+ os.path.normpath(rf'{self.temp_folder}\{n_}'),
55
+ 'w',
56
+ driver='GTiff',
57
+ height=Z.shape[0],
58
+ width=Z.shape[1],
59
+ count=1,
60
+ dtype=Z.dtype,
61
+ crs=self.crs,
62
+ transform=self.transform,
63
+ )
64
+
65
+ new_dataset.write(Z, 1)
66
+ new_dataset.close()
67
+
68
+
69
+
70
+ class MainWindow(QMainWindow):
71
+ def __init__(self):
72
+ super().__init__()
73
+ self.threadpool = QThreadPool.globalInstance()
74
+ self.setWindowTitle("Lineamentor - Lineament Extractor form large DEM")
75
+ # self.setGeometry(100, 100, 800, 600)
76
+
77
+
78
+ self.mainWidget = QWidget()
79
+ self.mainLayout = QHBoxLayout(self.mainWidget)
80
+
81
+ self.dem = None
82
+
83
+ self.setCentralWidget(self.mainWidget)
84
+
85
+ self.initLayout()
86
+
87
+ self.addFunctions()
88
+
89
+
90
+ def addFunctions(self):
91
+ self.openImageButton.clicked.connect(self.openFileAction)
92
+ self.subsetSideSlider.valueChanged.connect(self.gridUpdateAction)
93
+ self.resetButton.clicked.connect(self.resetAction)
94
+ self.previewRegen.clicked.connect(self.previewRegenActionAndSmallCalc)
95
+ self.extractButon.clicked.connect(self.extractLineamentAction)
96
+
97
+ self.previewImageOverlaySelector.currentIndexChanged.connect(self.previewRegenAction)
98
+ self.previewRegionSelector.currentIndexChanged.connect(self.previewRegenAction)
99
+ self.hillshadeAngleSelector.currentIndexChanged.connect(self.previewRegenAction)
100
+
101
+ self.previewRegionPointCheckbox.stateChanged.connect(self.previewRegenAction)
102
+ self.previewRegionLineDenseCheckbox.stateChanged.connect(self.previewRegenAction)
103
+ self.previewRegionLineCleanCheckbox.stateChanged.connect(self.previewRegenAction)
104
+
105
+
106
+
107
+ def initLayout(self):
108
+
109
+ middleSplitter = QSplitter()
110
+
111
+ self.mainLayout.addWidget(middleSplitter)
112
+
113
+
114
+ leftWidget = QWidget()
115
+ rightWidget = QWidget()
116
+ previewBigWidget = QWidget()
117
+ previewSmallWidget = QWidget()
118
+
119
+ leftLayout = QVBoxLayout(leftWidget)
120
+ rightLayout = QVBoxLayout(rightWidget)
121
+ righTab = QTabWidget()
122
+
123
+ previewBigLayout = QVBoxLayout(previewBigWidget)
124
+ previewSmallLayout = QVBoxLayout(previewSmallWidget)
125
+
126
+ middleSplitter.addWidget(leftWidget)
127
+ middleSplitter.addWidget(rightWidget)
128
+
129
+ rightLayout.addWidget(righTab)
130
+
131
+
132
+ righTab.addTab(previewBigWidget, 'overview', )
133
+ righTab.addTab(previewSmallWidget, 'extraction preview', )
134
+
135
+ # rightLayout.addLayout()
136
+
137
+ self.openImageButton = QPushButton('open image')
138
+ self.keepIntermediateCheckbox = QCheckBox()
139
+ keepIntermediatelayout = QHBoxLayout()
140
+ keepIntermediatelayout.addWidget(self.keepIntermediateCheckbox)
141
+ keepIntermediatelayout.addWidget(QLabel('keep intermediate file'))
142
+
143
+
144
+ self.resetButton = QPushButton('Reset to Default')
145
+ self.previewRegen = QPushButton('Regenerate Preview')
146
+ self.extractButon = QPushButton('Extract Lineament')
147
+
148
+ self.subsetSideSlider, subsetSideLabel, subsetSideLayout = self.add_slider("Image Subset size", 500, 100, 2000, 50)
149
+ self.downsampleSlider, downsampleLabel, downsampleLayout = self.add_slider("Downsample Factor", 1, 1, 20, 0.1)
150
+ self.hillshadeZSlider, hillshadeZLabel, hillshadeZLayout = self.add_slider("Hillshade Z", 0, -5, 5, 1,log=True)
151
+ self.epsSlider, epsLabel, epsLayout = self.add_slider("Eps", 1.2, 0.2, 4, 0.1)
152
+ self.threshSlider, threshLabel, threshLayout = self.add_slider("Thresh", 40, 10, 200, 1)
153
+ self.minDistSlider, minDistLabel, minDistLayout = self.add_slider("Min Dist", 10, 2, 100, 1)
154
+ self.segLenSlider, segLenLabel, segLenLayout = self.add_slider("Seg Len", 10, 2, 100, 1)
155
+
156
+ self.sliders = [self.subsetSideSlider, self.downsampleSlider,
157
+ self.hillshadeZSlider, self.epsSlider, self.threshSlider,
158
+ self.minDistSlider, self.segLenSlider, ]
159
+
160
+
161
+
162
+ self.previewImageOverlaySelector = QComboBox()
163
+ self.previewImageOverlaySelector.addItems(['orginial image',
164
+ 'Downscaled image',
165
+ 'Prewitt Filters',
166
+ 'Prewitt Filters Cutoff',
167
+ 'Hillshade',
168
+ ])
169
+
170
+ self.previewRegionSelector = QComboBox()
171
+ self.previewRegionSelector.addItems(['0'])
172
+
173
+ self.hillshadeAngleSelector = QComboBox()
174
+
175
+ n = 16
176
+ d = 360/n
177
+ for i in range(0, n):
178
+ deg1 = i*d
179
+ deg2 = deg1 + d
180
+ self.hillshadeAngleSelector.addItem(f'{deg1} - {deg2}')
181
+
182
+
183
+
184
+ previewSmallMenuWidget = QWidget()
185
+ previewSmallMenuWidget.setFixedHeight(120)
186
+ previewSmallMenuLayout = QHBoxLayout(previewSmallMenuWidget)
187
+
188
+ previewSmallLayout.addWidget(previewSmallMenuWidget)
189
+
190
+
191
+ col1previewSmallMenuLayout = QVBoxLayout()
192
+ col2previewSmallMenuLayout = QVBoxLayout()
193
+ col3previewSmallMenuLayout = QVBoxLayout()
194
+
195
+ previewSmallMenuLayout.addLayout(col1previewSmallMenuLayout)
196
+ previewSmallMenuLayout.addLayout(col2previewSmallMenuLayout)
197
+ previewSmallMenuLayout.addLayout(col3previewSmallMenuLayout)
198
+
199
+ previewSmallMenuLayout.addStretch()
200
+
201
+ def createLabelCheckbox(labelText:str):
202
+ label = QLabel(f'{labelText}')
203
+ checkbox = QCheckBox()
204
+ layout = QHBoxLayout()
205
+ layout.addWidget(checkbox)
206
+ layout.addWidget(label)
207
+
208
+ return checkbox, layout
209
+
210
+ self.previewRegionPointCheckbox, previewRegionPointLayout = createLabelCheckbox('Show/hide Extracted Point Features')
211
+ self.previewRegionLineDenseCheckbox, previewRegionLineDenseLayout = createLabelCheckbox('Show/hide Generate Lines Features')
212
+ self.previewRegionLineCleanCheckbox, previewRegionLineCleanLayout = createLabelCheckbox('Show/hide Aggregated Lines Features')
213
+
214
+ self.previewRegionPointCheckbox.setChecked(False)
215
+ self.previewRegionLineDenseCheckbox.setChecked(False)
216
+ self.previewRegionLineCleanCheckbox.setChecked(True)
217
+
218
+
219
+ # col1previewSmallMenuLayout.addWidget()
220
+
221
+ col1previewSmallMenuLayout.addWidget(QLabel('Preview Region Selector:'))
222
+ col1previewSmallMenuLayout.addWidget(self.previewRegionSelector)
223
+
224
+ col1previewSmallMenuLayout.addWidget(QLabel('Hillshade Angle Selector:'))
225
+ col1previewSmallMenuLayout.addWidget(self.hillshadeAngleSelector)
226
+
227
+
228
+ col2previewSmallMenuLayout.addStretch()
229
+ col2previewSmallMenuLayout.addWidget(QLabel('Preview Image overlay:'))
230
+ col2previewSmallMenuLayout.addWidget(self.previewImageOverlaySelector)
231
+ col2previewSmallMenuLayout.addLayout(previewRegionPointLayout)
232
+ col2previewSmallMenuLayout.addLayout(previewRegionLineDenseLayout)
233
+ col2previewSmallMenuLayout.addLayout(previewRegionLineCleanLayout)
234
+
235
+ col3previewSmallMenuLayout.addStretch()
236
+ col3previewSmallMenuLayout.addWidget(self.previewRegen)
237
+
238
+
239
+ leftLayout.addWidget(self.openImageButton)
240
+ leftLayout.addLayout(keepIntermediatelayout)
241
+
242
+ leftLayout.addLayout(subsetSideLayout)
243
+ leftLayout.addLayout(downsampleLayout)
244
+ leftLayout.addLayout(hillshadeZLayout)
245
+ leftLayout.addLayout(epsLayout)
246
+ leftLayout.addLayout(threshLayout)
247
+ leftLayout.addLayout(minDistLayout)
248
+ leftLayout.addLayout(segLenLayout)
249
+
250
+ leftLayout.addWidget(self.resetButton)
251
+ # leftLayout.addWidget(self.previewRegen)
252
+ leftLayout.addStretch()
253
+ leftLayout.addWidget(self.extractButon)
254
+
255
+
256
+
257
+ self.previewBigImg = pg.plot()
258
+ self.previewBigImg.setAspectLocked(True)
259
+ previewBigLayout.addWidget(self.previewBigImg)
260
+
261
+ self.previewSmallImg = pg.plot()
262
+ self.previewSmallImg.setAspectLocked(True)
263
+ previewSmallLayout.addWidget(self.previewSmallImg)
264
+
265
+
266
+ def loadImageAndPreview(self):
267
+ sz = self.subsetSideSlider.value() * self.subsetSideSlider.step
268
+
269
+ self.regions, self.dem, self.extent, self.crs_espg = read_raster(self.file_name, split_size=sz)
270
+
271
+ L,R,B,T = self.extent
272
+
273
+ if (L == 0) & (T==0):
274
+ L,R,T,B = self.extent
275
+
276
+
277
+ W, H = abs(L-R), abs(B-T)
278
+ img = pg.ImageItem(self.dem[::-1].T)
279
+ img.setRect(L,B,W,H)
280
+
281
+ self.previewBigImg.clear()
282
+ self.previewBigImg.addItem(img)
283
+
284
+ xarr = []
285
+ yarr = []
286
+
287
+ for l,b,r,t in self.regions.values[:,-4:]:
288
+ xarr = xarr + [l, r, r, l, l]
289
+ yarr = yarr + [t, t, b, b, t]
290
+
291
+ xarr = np.array(xarr)
292
+ yarr = np.array(yarr)
293
+ conn = np.ones_like(xarr,dtype=bool)
294
+
295
+ conn[4::5] = 0
296
+
297
+ girdArr = pg.arrayToQPath(xarr, yarr, connect=conn)
298
+
299
+ self.girditem = pg.QtWidgets.QGraphicsPathItem(girdArr)
300
+ self.girditem.setPen(pg.mkPen('y', width=1))
301
+ self.previewBigImg.addItem(self.girditem)
302
+
303
+ self.tx_plot_collection = []
304
+
305
+ for num, (l,b,r,t) in enumerate(self.regions.values[:,-4:]):
306
+ tx = pg.TextItem(str(num).zfill(5), color='yellow',anchor=(0.5,0.5))
307
+ tx.setPos((l+r)/2, (t+b)/2)
308
+ self.tx_plot_collection.append(tx)
309
+
310
+ self.previewBigImg.addItem(tx)
311
+
312
+ self.previewBigImg.enableAutoRange()
313
+
314
+
315
+ self.previewRegionSelector.clear()
316
+ self.previewRegionSelector.addItems([str(n).zfill(5) for n in range(len(self.regions))])
317
+
318
+ self.previewRegenAction()
319
+
320
+
321
+ def gridUpdateAction(self):
322
+
323
+ sz = self.subsetSideSlider.value() * self.subsetSideSlider.step
324
+
325
+ shape = self.dem.shape
326
+ left, bottom, right, top = self.extent[0], self.extent[2], self.extent[1], self.extent[3]
327
+ resX = (right-left)/self.dem.shape[1]
328
+ resY = (top-bottom)/self.dem.shape[0]
329
+
330
+
331
+ v_split = np.c_[np.arange(0, shape[0]-sz, sz), np.arange(0, shape[0]-sz, sz)+sz]
332
+ v_split = np.vstack([v_split, [v_split[-1,-1],shape[0]]])
333
+
334
+
335
+ h_split = np.c_[np.arange(0, shape[1]-sz, sz), np.arange(0, shape[1]-sz, sz)+sz]
336
+ h_split = np.vstack([h_split, [h_split[-1,-1],shape[1]]])
337
+
338
+ xx, yy = np.meshgrid(np.arange(len(v_split)), np.arange(len(h_split)))
339
+ xx, yy = xx.flatten(), yy.flatten()
340
+
341
+ grids = np.c_[ h_split[yy], v_split[xx],]
342
+ '''grid format: [[L, R, B, T]] '''
343
+
344
+ ns = np.arange(len(grids))
345
+ lefts = [left]*len(grids)
346
+ tops = [top]*len(grids)
347
+ resXs = [resX]*len(grids)
348
+ resYs = [resY]*len(grids)
349
+ szs = [sz]*len(grids)
350
+
351
+ self.regions = pd.DataFrame(zip(ns, lefts, tops, resXs, resYs, szs), columns=['ns', 'lefts', 'tops', 'resXs', 'resYs', 'szs'])
352
+
353
+ self.regions[['L', 'R', 'B', 'T']] = grids
354
+
355
+ self.regions['left_bound'] = self.regions['lefts'] + self.regions['L']*self.regions['resXs']
356
+ self.regions['bottom_bound'] = self.regions['tops'] - self.regions['T']*self.regions['resYs']
357
+ self.regions['right_bound'] = self.regions['left_bound'] + abs(self.regions['L'] - self.regions['R'])*self.regions['resXs']
358
+ self.regions['top_bound'] = self.regions['bottom_bound'] + abs(self.regions['T'] - self.regions['B'])*self.regions['resYs']
359
+
360
+ xarr = []
361
+ yarr = []
362
+
363
+
364
+ for tx in self.tx_plot_collection:
365
+ tx.setText('')
366
+
367
+ for num, (l,b,r,t) in enumerate(self.regions.values[:,-4:]):
368
+ xarr = xarr + [l, r, r, l, l]
369
+ yarr = yarr + [t, t, b, b, t]
370
+
371
+ if num<len(self.tx_plot_collection):
372
+ tx = self.tx_plot_collection[num]
373
+ tx.setText(str(num).zfill(5))
374
+ tx.setPos((l+r)/2, (t+b)/2)
375
+
376
+ else:
377
+ tx = pg.TextItem(str(num).zfill(5), color='yellow',anchor=(0.5,0.5))
378
+ tx.setPos((l+r)/2, (t+b)/2)
379
+ self.previewBigImg.addItem(tx)
380
+ self.tx_plot_collection.append(tx)
381
+
382
+ # tx = pg.TextItem(str(num).zfill(5), color='yellow',anchor=(0.5,0.5))
383
+ # tx.setPos((l+r)/2, (t+b)/2)
384
+ # tx.setAnchor
385
+ xarr = np.array(xarr)
386
+ yarr = np.array(yarr)
387
+ conn = np.ones_like(xarr,dtype=bool)
388
+
389
+ conn[4::5] = 0
390
+
391
+ p = pg.arrayToQPath(xarr, yarr, connect=conn)
392
+
393
+ self.girditem.setPath(p)
394
+
395
+ self.previewRegionSelector.clear()
396
+ self.previewRegionSelector.addItems([str(n).zfill(5) for n in range(len(self.regions))])
397
+
398
+
399
+ def openFileAction(self):
400
+ options = QFileDialog.Options()
401
+ self.file_name, _ = QFileDialog.getOpenFileName(self, "Open File", "", "Georeferenced image (*.tif);;Georeferenced image (*.tiff);;Non Georef image (*.jpeg);;Non Georef image (*.jpg)", options=options)
402
+ if self.file_name:
403
+ self.loadImageAndPreview()
404
+
405
+
406
+ def resetAction(self):
407
+
408
+ self.keepIntermediateCheckbox.setChecked(False)
409
+ for it in self.sliders:
410
+ it.setValue(int(it.default / it.step))
411
+
412
+
413
+ def previewRegenActionAndSmallCalc(self):
414
+ self.smallCalc()
415
+ self.previewRegenAction()
416
+
417
+
418
+ def previewRegenAction(self):
419
+ self.previewSmallImg.clear()
420
+ self.getImageSubset()
421
+
422
+
423
+ overlay = self.previewImageOverlaySelector.currentText()
424
+ hs = self.hillshadeAngleSelector.currentText()
425
+ hs = hs.replace(' ', '').split('-')
426
+ avgAng = (float(hs[0]) + float(hs[1])) /2
427
+
428
+
429
+ if overlay == 'original image':
430
+ img = self.demSubset
431
+
432
+ elif overlay == 'Prewitt Filters':
433
+ img = self.im_prewitt
434
+
435
+ elif overlay == 'Prewitt Filters Cutoff':
436
+ img = self.im_prewitt_clip
437
+
438
+ elif overlay == 'Hillshade':
439
+ z_multip = round(10**(self.hillshadeZSlider.value() * self.hillshadeZSlider.step),5)
440
+ img = hillshade(self.demSubset, azimuth=avgAng, z_multip=z_multip)
441
+
442
+ else:
443
+ img = self.demSubset
444
+
445
+ subImg = pg.ImageItem(img.T[:,::-1])
446
+ self.previewSmallImg.addItem(subImg)
447
+
448
+ showPoints = self.previewRegionPointCheckbox.checkState() > 0
449
+ showLine = self.previewRegionLineDenseCheckbox.checkState() > 0
450
+ showcleanLine = self.previewRegionLineCleanCheckbox.checkState() > 0
451
+
452
+ c = [(202, 174, 209),
453
+ (203, 51, 10),
454
+ (62, 145, 52),
455
+ (187, 97, 69),
456
+ (148, 46, 4),
457
+ (63, 117, 56),
458
+ (68, 204, 91),
459
+ (5, 55, 99),
460
+ (16, 21, 21),
461
+ (39, 107, 151),
462
+ (202, 174, 209),
463
+ (203, 51, 10),
464
+ (62, 145, 52),
465
+ (187, 97, 69),
466
+ (148, 46, 4),
467
+ (63, 117, 56),
468
+ (68, 204, 91),
469
+ (5, 55, 99),
470
+ (16, 21, 21),
471
+ (39, 107, 151)]
472
+
473
+
474
+ if showPoints:
475
+ for num, df in enumerate(self.container):
476
+ p = pg.ScatterPlotItem(df['X'], img.shape[0]-df['Y'],
477
+ pen = None,
478
+ brush=c[num],
479
+ symbol ='o',
480
+ size = 5,
481
+ name =f'quadrant: {num}')
482
+ p.setBrush(c[num])
483
+ p.setPen(None)
484
+
485
+ self.previewSmallImg.addItem(p)
486
+
487
+ if showLine:
488
+ self.line_all = pg.QtWidgets.QGraphicsPathItem()
489
+ self.line_all.setPen(pg.mkPen('r', width=3))
490
+
491
+ lines_ = self.lines[['min_x', 'max_x', 'min_y', 'max_y']].values
492
+ xarr_line = np.ones(len(lines_)*2)
493
+ yarr_line = np.ones(len(lines_)*2)
494
+ conn_line = np.ones(len(lines_)*2)
495
+ xarr_line[::2] = lines_[:,0]
496
+ xarr_line[1::2] = lines_[:,1]
497
+ yarr_line[::2] = lines_[:,2]
498
+ yarr_line[1::2] = lines_[:,3]
499
+ conn_line[1::2] = 0
500
+ line_plot = pg.arrayToQPath(xarr_line, img.shape[0]-yarr_line, connect=conn_line)
501
+ self.line_all.setPath(line_plot)
502
+ self.previewSmallImg.addItem(self.line_all)
503
+
504
+ if showcleanLine:
505
+
506
+ self.line_all_sieve = pg.QtWidgets.QGraphicsPathItem()
507
+ self.line_all_sieve.setPen(pg.mkPen('b', width=3))
508
+
509
+ lines_ = self.broken_lines[['min_x', 'max_x', 'min_y', 'max_y']].values
510
+ xarr_line = np.ones(len(lines_)*2)
511
+ yarr_line = np.ones(len(lines_)*2)
512
+ conn_line = np.ones(len(lines_)*2)
513
+ xarr_line[::2] = lines_[:,0]
514
+ xarr_line[1::2] = lines_[:,1]
515
+ yarr_line[::2] = lines_[:,2]
516
+ yarr_line[1::2] = lines_[:,3]
517
+ conn_line[1::2] = 0
518
+ line_plot = pg.arrayToQPath(xarr_line, img.shape[0]-yarr_line, connect=conn_line)
519
+ self.line_all_sieve.setPath(line_plot)
520
+ self.previewSmallImg.addItem(self.line_all_sieve)
521
+
522
+ self.previewSmallImg.enableAutoRange()
523
+
524
+
525
+ def getImageSubset(self):
526
+
527
+ sz = self.subsetSideSlider.value() * self.subsetSideSlider.step
528
+ z_multip = round(10**(self.hillshadeZSlider.value() * self.hillshadeZSlider.step),5)
529
+ eps = self.epsSlider.value() * self.epsSlider.step
530
+ thresh = self.threshSlider.value() * self.threshSlider.step
531
+ min_dist = self.minDistSlider.value() * self.minDistSlider.step
532
+ seg_len = self.segLenSlider.value() * self.segLenSlider.step
533
+ downsacale = self.downsampleSlider.value() * self.downsampleSlider.step
534
+
535
+ selected_region = int(self.previewRegionSelector.currentText())
536
+ curr = self.regions[self.regions['ns'] == selected_region]
537
+
538
+ curr = self.regions.iloc[selected_region]
539
+
540
+ L, R, B, T = int(curr['L']), int(curr['R']), int(curr['B']), int(curr['T'])
541
+
542
+ dem = self.dem[B:T, L:R]
543
+ self.demSubsetOrig = dem.copy()
544
+ dem_min, dem_max = dem.min(), dem.max()
545
+ dem = rescale(dem, 1/downsacale, anti_aliasing=False)
546
+ dem2_min, dem2_max = dem.min(), dem.max()
547
+ dem = (dem - dem2_min)/(dem2_max - dem2_min)
548
+ dem = dem_min + dem*(dem_max-dem_min)
549
+ self.demSubset = dem.copy()
550
+
551
+
552
+ def smallCalc(self):
553
+
554
+ sz = self.subsetSideSlider.value() * self.subsetSideSlider.step
555
+ z_multip = round(10**(self.hillshadeZSlider.value() * self.hillshadeZSlider.step),5)
556
+ eps = self.epsSlider.value() * self.epsSlider.step
557
+ thresh = self.threshSlider.value() * self.threshSlider.step
558
+ min_dist = self.minDistSlider.value() * self.minDistSlider.step
559
+ seg_len = self.segLenSlider.value() * self.segLenSlider.step
560
+ downsacale = self.downsampleSlider.value() * self.downsampleSlider.step
561
+
562
+ selected_region = int(self.previewRegionSelector.currentText())
563
+ curr = self.regions[self.regions['ns'] == selected_region]
564
+
565
+ curr = self.regions.iloc[selected_region]
566
+
567
+ L, R, B, T = int(curr['L']), int(curr['R']), int(curr['B']), int(curr['T'])
568
+
569
+ # dem = self.dem[B:T, L:R]
570
+ self.getImageSubset()
571
+
572
+
573
+ extent = [0, self.demSubset.shape[1], self.demSubset.shape[0],0]
574
+
575
+ self.container, self.im_prewitt, self.im_prewitt_clip =extract_lineament_points(self.demSubset,
576
+ eps=eps,
577
+ thresh=thresh,
578
+ z_multip=z_multip)
579
+ self.lines = convert_points_to_line(self.container)
580
+
581
+ _,_, self.broken_lines = reduce_lines(self.lines, extent,
582
+ self.demSubset.shape,
583
+ min_dist=min_dist,
584
+ seg_len=seg_len)
585
+
586
+
587
+ def add_slider(self, name, default, min_val, max_val, step, log=False):
588
+
589
+ if log:
590
+ label = QLabel(f"{name}: {10**default}")
591
+ else:
592
+ label = QLabel(f"{name}: {default}")
593
+
594
+ slider = QSlider(Qt.Horizontal)
595
+ slider.setMinimum(int(min_val / step))
596
+ slider.setMaximum(int(max_val / step))
597
+ slider.setValue(int(default / step))
598
+ slider.setTickInterval(1)
599
+ slider.setSingleStep(1)
600
+ slider.step = step
601
+ slider.min_val = min_val
602
+ slider.max_val = max_val
603
+ slider.name = name
604
+ slider.default = default
605
+
606
+
607
+ if log:
608
+ slider.valueChanged.connect(lambda value: label.setText(f"{name}: {10**(value * step)}"))
609
+
610
+ else:
611
+ if type(step) == int:
612
+ slider.valueChanged.connect(lambda value: label.setText(f"{name}: {value * step} "))
613
+ else:
614
+ slider.valueChanged.connect(lambda value: label.setText(f"{name}: {round((value * step), 3)} "))
615
+
616
+ layout = QVBoxLayout()
617
+ layout.addWidget(label)
618
+ layout.addWidget(slider)
619
+
620
+ return slider, label, layout
621
+
622
+
623
+ def extractLineamentAction(self):
624
+ import glob
625
+ import rasterio
626
+
627
+ options = QFileDialog.Options()
628
+ shp_path, _ = QFileDialog.getSaveFileName(self, "Shapefile Name", "", "Shapefile (*.shp);", options=options)
629
+ shp_name = os.path.split(shp_path)[-1]
630
+ n = shp_name.split('.')[0]
631
+ temp_folder = os.path.normpath(shp_path.replace(shp_name,'')+ f'\\{n}')
632
+
633
+ im_path = os.path.normpath(self.file_name)
634
+
635
+ sz = self.subsetSideSlider.value() * self.subsetSideSlider.step
636
+ z_multip = round(10**(self.hillshadeZSlider.value() * self.hillshadeZSlider.step),5)
637
+ eps = self.epsSlider.value() * self.epsSlider.step
638
+ thresh = self.threshSlider.value() * self.threshSlider.step
639
+ min_dist = self.minDistSlider.value() * self.minDistSlider.step
640
+ seg_len = self.segLenSlider.value() * self.segLenSlider.step
641
+ downscale = self.downsampleSlider.value() * self.downsampleSlider.step
642
+
643
+ keep_intermediate_file = self.keepIntermediateCheckbox.checkState() > 0
644
+
645
+
646
+ if os.path.isdir(temp_folder):
647
+ 'delete content'
648
+ files = glob.glob(f'{temp_folder}/*')
649
+ for f in files:
650
+ os.remove(f)
651
+ else:
652
+ 'create new folder'
653
+ os.mkdir(temp_folder)
654
+
655
+
656
+ ''' IMAGE SPLITTING SEQUENCES - START'''
657
+ #==================================================================================================
658
+ dataset = rasterio.open(im_path)
659
+ im = dataset.read(1)
660
+ shape = im.shape
661
+ left, bottom, right, top = list(dataset.bounds)
662
+ resX = (right-left)/im.shape[1]
663
+ resY = (top-bottom)/im.shape[0]
664
+
665
+ if shape[0]<sz:
666
+ v_split = np.array([[0, shape[0]]])
667
+ else:
668
+ v_split = np.c_[np.arange(0, shape[0]-sz, sz), np.arange(0, shape[0]-sz, sz)+sz]
669
+ v_split = np.vstack([v_split, [v_split[-1,-1],shape[0]]])
670
+
671
+ if shape[1]<sz:
672
+ h_split = np.array([[0, shape[1]]])
673
+ else:
674
+ h_split = np.c_[np.arange(0, shape[1]-sz, sz), np.arange(0, shape[1]-sz, sz)+sz]
675
+ h_split = np.vstack([h_split, [h_split[-1,-1],shape[1]]])
676
+
677
+
678
+ xx, yy = np.meshgrid(np.arange(len(v_split)), np.arange(len(h_split)))
679
+ xx, yy = xx.flatten(), yy.flatten()
680
+
681
+ grids = np.c_[ h_split[yy], v_split[xx],]
682
+ #==================================================================================================
683
+
684
+ '''grid format: [[L, R, B, T]] '''
685
+
686
+
687
+ ns = np.arange(len(grids))
688
+ target_folders = [temp_folder]*len(grids)
689
+ lefts = [left]*len(grids)
690
+ tops = [top]*len(grids)
691
+ resXs = [resX]*len(grids)
692
+ resYs = [resY]*len(grids)
693
+ szs = [sz]*len(grids)
694
+
695
+ df = pd.DataFrame(zip(ns, target_folders, lefts, tops, resXs, resYs, szs), columns=['ns', 'target_folders', 'lefts', 'tops', 'resXs', 'resYs', 'szs'])
696
+
697
+ df[['L', 'R', 'B', 'T']] = grids
698
+
699
+ transforms = []
700
+ ims = []
701
+
702
+ for n, tempfolder, left, top, resX, resY, sz, L, R, B, T in df.values:
703
+ l = left + L*resX
704
+ # b = top - T*resY - sz*resY
705
+ b = top + T*resY
706
+
707
+ transform = rasterio.Affine.translation(l - resX / 2, b + resY / 2) * rasterio.Affine.scale(resX, resY)
708
+ Z = im[B:T, L:R].astype('float')
709
+
710
+ transforms.append(transform)
711
+ ims.append(Z)
712
+
713
+ crs = dataset.crs
714
+ self.df = df
715
+
716
+
717
+
718
+ cases = zip(np.arange(len(df)),
719
+ [crs]*len(df),
720
+ ims,
721
+ transforms,
722
+ [temp_folder]*len(df))
723
+ for n_, crs, im, transform, temp_folder in cases:
724
+ worker = ImageSplitterParallel(n_, crs, im, transform, temp_folder)
725
+ self.threadpool.start(worker)
726
+
727
+ print(''' IMAGE SPLITTING SEQUENCES - END''' )
728
+
729
+ self.threadpool.waitForDone()
730
+
731
+
732
+ flist = glob.glob(f'{temp_folder}/*.tiff')
733
+ cases = pd.DataFrame(zip(flist,
734
+ [temp_folder]*len(flist),
735
+ [eps]*len(flist),
736
+ [thresh]*len(flist),
737
+ [min_dist]*len(flist),
738
+ [seg_len]*len(flist),
739
+ [z_multip]*len(flist),
740
+ [downscale]*len(flist))).values
741
+
742
+ from joblib import Parallel, delayed
743
+ Parallel(n_jobs=-1)(delayed(dem_to_line)(*c) for c in cases)
744
+
745
+ df = merge_lines_csv_to_shp(tempfolder=temp_folder,
746
+ shppath=shp_path,
747
+ save_to_file=True)
748
+
749
+
750
+ if keep_intermediate_file == False:
751
+
752
+ if os.path.isdir(tempfolder):
753
+ 'delete content'
754
+ files = glob.glob(f'{tempfolder}/*')
755
+ for f in files:
756
+ os.remove(f)
757
+ os.removedirs(tempfolder)
758
+
759
+
760
+
761
+ if __name__ == "__main__":
762
+ app = QApplication(sys.argv)
763
+ window = MainWindow()
764
+ window.show()
765
+ sys.exit(app.exec_())
766
+