-
Notifications
You must be signed in to change notification settings - Fork 0
/
CarolinaHurtado_ProjectMain.html
349 lines (316 loc) · 18.6 KB
/
CarolinaHurtado_ProjectMain.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Carolina Hurtado-Pulido</title>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<!--Styles for text along the document-->
<style>
h1 {text-align: center;
color: #134f5c;
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size:250%}
h2 {font-family: Verdana, Geneva, Tahoma, sans-serif;
margin-left: 70px;}
h3 {font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 150%;
margin-left: 70px;}
p {font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 120%;
margin-left: 150px;
margin-right: 150px;}
canvas {border: 3px solid #444444;
margin: 15px;}
</style>
<h1>Compare Pixel Values Interactively</h1>
<div>
<h2>Carolina Hurtado-Pulido</h2>
<h3>Data Visualization -Final project</h3>
<h3>Spring/2022 (May/8/2022)</h3>
<hr size="3">
<p><b>Justification:</b> I did this project to be able to visualize more than one image
at a time in an easy way and obtain some basic information simultaneously.<br>
I chose to do this project because I am constantly seeing different images in the
same area. GIS software allows me to do analysis and visualization, but there are times
when I only need to look at the information in a window rapidly. This tool allows the
user to obtain information on one pixel of interest or from multiple pixels on both
screens. If the user selects one pixel in either of the windows, will obtain the <b>subsidence
or uplifting range</b> on the left screen, and the <b>elevation range</b> on the right screen. If the
user selects a region will obtain the <b>dominant subsidence or uplifting range, dominant elevation
range, and the number of pixels in selected the area.</b> <br><br>
Here, I am presenting a Digital elevation model Of Differences - DOF - with information
about elevation change in Baton Rouge between 1999 and 2018 <i>(left)</i> and a Digital
Elevation Model - DEM- with elevation information from 2018 <i>(right)</i>. The units
for both images, cover the same geographic area and have the same size (600 x 600 px).
White areas do not have information. I created these figures as part of my research. <br><br>
For more information about the code please go to <a href="https://github.com/Carolinah23/Project_DataVisualization">link to my GithHub repository</a>
</p>
<p><b>Intructions:</b> <br>
1) To have information from an unique pixel: Double click on any of the images. <br>
2) To have information from a region of interes: Drag your mouse on any of the
images and let go. This will create a region in both images. <br>
3) To clean: Click on any of the screens, or just do any of the actions explained above.
</p>
</div>
<div id="container" style= "text-align:center;">
<image style="display: none;" id="diff" src="./Images/Diff.jpg"/>
<image style="display: none;" id="dem" src="./Images/DEM.jpg"/>
<canvas id="canvas_first" width="600" height="600" ></canvas>
<image id="diff_legend" src="./Images/Legend_diff.jpg" width="200", height="250"/>
<canvas id="canvas_second" width="600" height="600"></canvas>
<image id="dem_legend" src="./Images/Legend_dem.jpg" width="200", height="250"/>
</div>
<script>
//Load images on canvas https://www.w3schools.com/tags/canvas_drawimage.asp
window.onload=function(){
var canvas1=document.getElementById("canvas_first");
var canvas2=document.getElementById("canvas_second");
var context1=canvas1.getContext("2d");
var context2=canvas2.getContext("2d");
var fig_diff=document.getElementById("diff");
var fig_dem=document.getElementById("dem");
context1.drawImage(fig_diff, 0,0);
context2.drawImage(fig_dem, 0,0);
context1.font=context2.font="20px Arial";
//Event for one pixel
canvas1.addEventListener("dblclick", function(event){
var eventCoordinates=MouseEventLocation(this,event);
var pixelData=context1.getImageData(eventCoordinates.x, eventCoordinates.y, 1,1).data;
var pixelData_right=context2.getImageData(eventCoordinates.x, eventCoordinates.y, 1,1).data;
//No data values
if ((pixelData[0]==255)&&(pixelData[1]==255)&&(pixelData[2]==255)&&(pixelData[3]==255)){
context1.fillStyle = context2.fillStyle= "#ffffff";
context1.fillRect(0, 550, 600, 50);
context1.fillStyle = "#000000";
context2.fillRect(0, 550, 600, 50);
context2.fillStyle = "#000000";
context1.fillText("NaN value",10,580);
context2.fillText("NaN value",10,580);
console.log("NaN value");
}
else{
context1.fillStyle = "#ffffff";
context1.fillRect(0, 550, 600, 50);
context1.fillStyle = "#000000";
context2.fillStyle = "#ffffff";
context2.fillRect(0, 550, 600, 50);
context2.fillStyle = "#000000";
ClassificationLeft(context1, Min_ColorDistance_left(pixelData[0],pixelData[1],pixelData[2]));
ClassificationRight(context2, Min_ColorDistance_right(pixelData_right[0],pixelData_right[1],pixelData_right[2]));
}
})
//Events for region of pixels
canvas1.addEventListener("mousedown", function(event){
coord_start=MouseEventLocation(this, event);
context1.drawImage(fig_diff, 0,0);
context2.drawImage(fig_dem, 0,0);
context2.fillStyle = "#ffffff";
context1.fillStyle = "#ffffff";
context2.fillRect(0, 550, 600, 50);
context1.fillRect(0, 550, 600, 50);
})
canvas1.addEventListener("mouseup", function(event){
coord_end=MouseEventLocation(this, event);
EventConection_Down(context1, context2, coord_start.x, coord_start.y, coord_end.x, coord_end.y);
//context1.fillText("Mean Red:"+Red_Stats[0]+" Std Red:"+Red_Stats[1],10,580);
})
//Event for one pixel
canvas2.addEventListener("dblclick", function(event){
var eventCoordinates=MouseEventLocation(this,event);
var pixelData=context2.getImageData(eventCoordinates.x, eventCoordinates.y, 1,1).data;
var pixelData_left=context1.getImageData(eventCoordinates.x, eventCoordinates.y, 1,1).data;
//No data values
if ((pixelData[0]==255)&&(pixelData[1]==255)&&(pixelData[2]==255)&&(pixelData[3]==255)){
context2.fillStyle = "#ffffff";
context2.fillRect(0, 550, 600, 50);
context2.fillStyle = "#000000";
context1.fillStyle = "#ffffff";
context1.fillRect(0, 550, 600, 50);
context1.fillStyle = "#000000";
context2.fillText("NaN value",10,580);
context1.fillText("NaN value",10,580);
console.log("NaN value");
}
else{
context2.fillStyle = "#ffffff";
context2.fillRect(0, 550, 600, 50);
context2.fillStyle = "#000000";
context1.fillStyle = "#ffffff";
context1.fillRect(0, 550, 600, 50);
context1.fillStyle = "#000000";
ClassificationRight(context2, Min_ColorDistance_right(pixelData[0],pixelData[1],pixelData[2]));
ClassificationLeft(context1, Min_ColorDistance_left(pixelData_left[0],pixelData_left[1],pixelData_left[2]));
}
})
//Events for region of pixels
canvas2.addEventListener("mousedown", function(event){
coord_start=MouseEventLocation(this, event);
context2.fillStyle = "#ffffff";
context1.fillStyle = "#ffffff";
context1.drawImage(fig_diff, 0,0);
context2.drawImage(fig_dem, 0,0);
context2.fillRect(0, 550, 600, 50);
context1.fillRect(0, 550, 600, 50);
})
canvas2.addEventListener("mouseup", function(event){
coord_end=MouseEventLocation(this, event);
EventConection_Down(context1, context2, coord_start.x, coord_start.y, coord_end.x, coord_end.y);
//context1.fillText("Mean Red:"+Red_Stats[0]+" Std Red:"+Red_Stats[1],10,580);
})
}
//Function to return of an object (canvas) in the document
function CanvasPosition(obj){
var horizontal=0
var vertical=0
if(obj.offsetParent){
do{
horizontal+=obj.offsetLeft;
vertical+=obj.offsetTop;
}while (obj=obj.offsetParent);
return {x:horizontal, y:vertical};
}
return undefined;
}
//Function to locate mouse event on canvas
function MouseEventLocation(object, event){
var position=CanvasPosition(object);
return{
x:(event.pageX-position.x), y:(event.pageY-position.y)
};
}
//Function to enclose pixels in a rectangle
function drawRectangle(canvasContext, x, y, rect_width, rect_height){
canvasContext.beginPath();
canvasContext.rect(x, y, rect_width, rect_height);
canvasContext.stroke();
}
//function to find pixels in a region
function findPixels(canvasContext, x, y, rect_width, rect_height) {
var ImageData = canvasContext.getImageData(x, y, rect_width, rect_height);
var dataLength=ImageData.data.length;
var Red=[];
var Green=[];
var Blue=[];
for(i=0; i<dataLength; i+=4){
Red.push(ImageData.data[i]);
Green.push(ImageData.data[i+1]);
Blue.push(ImageData.data[i+2]);
}
return [Red, Green, Blue];
}
//Function to calculate mean and standard deviation from region
function stats(array){
var sum=0;
var sum_Differences=0;
for (i=0; i<array.length;i++){
sum+=array[i];}
//Means
var Mean=sum/array.length;
//std
for(i=0; i<array.length;i++){
sum_Differences+=(array[i]-Mean);
}
var Std=sum_Differences/array.length;
return [Mean.toFixed(3), Std.toFixed(5)];
}
//Function to find the closest color using the classes from QGIS - image left
function Min_ColorDistance_left(R,G,B){
var df=[178, 24, 43, 239, 138, 98, 253, 219, 199, 255, 255, 191, 209, 229, 240, 103, 169, 207, 33, 102, 172, 0, 39, 118];
var distances=[];
for(i=0; i<df.length;i+=3){
distances.push(Math.sqrt(((R-df[i])*(R-df[i]))+((G-df[i+1])*(G-df[i+1]))+((B-df[i+2])*(B-df[i+2]))));
}
var closest_distance=Math.min(...distances);
var closest_index=distances.indexOf(closest_distance);
return closest_index;
}
//Function to classify pixel on change ranges
function ClassificationLeft(ctx, index_min_left){
if (index_min_left==0){ctx.fillText("Subsidence between -1 to -0.75 m",10,580);}
else if (index_min_left==1){ctx.fillText("Subsidence between -0.75 to -0.5 m",10,580);}
else if (index_min_left==2){ctx.fillText("Subsidence between -0.5 to -0.25 m",10,580);}
else if (index_min_left==3){ctx.fillText("Subsidence between -0.25 to 0 m",10,580);}
else if (index_min_left==4){ctx.fillText("Uplifting between 0 to 0.25 m",10,580);}
else if (index_min_left==5){ctx.fillText("Uplifting between 0.25 to 0.5 m",10,580);}
else if (index_min_left==6){ctx.fillText("Uplifting between 0.5 to 0.75 m",10,580);}
else if (index_min_left==7){ctx.fillText("Uplifting between 0.75 to 1 m",10,580);}
}
//Function to classify region on change ranges
function Mean_ClassificationLeft(ctx, index_min_left){
if (index_min_left==0){ctx.fillText("Dominant values between -1 to -0.75 m (subsidence)",10,570);}
else if (index_min_left==1){ctx.fillText("Dominant values between -0.75 to -0.5 m (subsidence)",10,570);}
else if (index_min_left==2){ctx.fillText("Dominant values between -0.5 to -0.25 m (subsidence)",10,570);}
else if (index_min_left==3){ctx.fillText("Dominant values between -0.25 to 0 m (subsidence)",10,570);}
else if (index_min_left==4){ctx.fillText("Dominant values between 0 to 0.25 m (uplifting)",10,570);}
else if (index_min_left==5){ctx.fillText("Dominant values between 0.25 to 0.5 m (uplifting)",10,570);}
else if (index_min_left==6){ctx.fillText("Dominant values between 0.5 to 0.75 m (uplifting)",10,570);}
else if (index_min_left==7){ctx.fillText("Dominant values between 0.75 to 1 m (uplifting)",10,570);}
}
//Function to find the closest color using the classes from QGIS - image left
function Min_ColorDistance_right(R,G,B){
var df=[1, 102, 94, 90, 180, 172, 199, 234, 229, 245, 245, 245, 246, 232, 195, 216, 179, 101, 140, 81, 10, 86, 50, 8];
var distances_r=[];
for(i=0; i<df.length;i+=3){
distances_r.push(Math.sqrt(((R-df[i])*(R-df[i]))+((G-df[i+1])*(G-df[i+1]))+((B-df[i+2])*(B-df[i+2]))));
}
var closest_distance_r=Math.min(...distances_r);
var closest_index_r=distances_r.indexOf(closest_distance_r);
console.log("distance "+ closest_distance_r + "index: "+ closest_index_r);
return closest_index_r;
}
//Function to classify pixel on elevations
function ClassificationRight(ctx, index_min_right){
if (index_min_right==0){ctx.fillText("Elevation between -4 to 0 m",10,580);}
else if (index_min_right==1){ctx.fillText("Elevation between 0 to 4 m",10,580);}
else if (index_min_right==2){ctx.fillText("Elevation between 4 to 8 m",10,580);}
else if (index_min_right==3){ctx.fillText("Elevation between 8 to 12 m",10,580);}
else if (index_min_right==4){ctx.fillText("Elevation between 12 to 16 m",10,580);}
else if (index_min_right==5){ctx.fillText("Elevation between 16 to 20 m",10,580);}
else if (index_min_right==6){ctx.fillText("Elevation between 20 to 24 m",10,580);}
else if (index_min_right==7){ctx.fillText("Elevation between 24 to 29 m",10,580);}
}
//Function to classify region on change ranges
function Mean_ClassificationRight(ctx, index_min_right){
if (index_min_right==0){ctx.fillText("Dominant elevation values between -4 to 0 m",10,570);}
else if (index_min_right==1){ctx.fillText("Dominant elevation values between 0 to 4 m",10,570);}
else if (index_min_right==2){ctx.fillText("Dominant elevation values between 4 to 8 m",10,570);}
else if (index_min_right==3){ctx.fillText("Dominant elevation values between 8 to 12 m",10,570);}
else if (index_min_right==4){ctx.fillText("Dominant elevation values between 12 to 16 m",10,570);}
else if (index_min_right==5){ctx.fillText("Dominant elevation values between 16 to 20 m",10,570);}
else if (index_min_right==6){ctx.fillText("Dominant elevation values between 20 to 24 m",10,570);}
else if (index_min_right==7){ctx.fillText("Dominant elevation values between 24 to 29 m",10,580);}
}
//Function to connect selection in canvas 1 and canvas 2
function EventConection_Down(ctx_left, ctx_right, x_mouse_start, y_mouse_start, x_mouse_end, y_mouse_end){
var RGB_left=[];
var RGB_right=[];
RGB_left=findPixels(ctx_left, x_mouse_start, y_mouse_start, (x_mouse_end-x_mouse_start), (y_mouse_end-y_mouse_start));
RGB_right=findPixels(ctx_right, x_mouse_start, y_mouse_start, (x_mouse_end-x_mouse_start), (y_mouse_end-y_mouse_start));
drawRectangle(ctx_left, x_mouse_start, y_mouse_start, (x_mouse_end-x_mouse_start), (y_mouse_end-y_mouse_start));
drawRectangle(ctx_right, x_mouse_start, y_mouse_start, (x_mouse_end-x_mouse_start), (y_mouse_end-y_mouse_start));
Red_Stats_right=stats(RGB_right[0]);
Green_Stats_right=stats(RGB_right[1]);
Blue_Stats_right=stats(RGB_right[2]);
Red_Stats_left=stats(RGB_left[0]);
Green_Stats_left=stats(RGB_left[1]);
Blue_Stats_left=stats(RGB_left[2]);
ctx_right.fillStyle = ctx_left.fillStyle ="#000000";
Mean_ClassificationLeft(ctx_left, Min_ColorDistance_left(Red_Stats_left[0],Green_Stats_left[0],Blue_Stats_left[0]));
Mean_ClassificationRight(ctx_right, Min_ColorDistance_right(Red_Stats_right[0],Green_Stats_right[0],Blue_Stats_right[0]));
ctx_left.fillText("("+RGB_right[0].length+" pixels)",10,595);
ctx_right.fillText("("+RGB_right[0].length+" pixels)",10,595)
}
</script>
<p><b>Calculation explination:</b> I created each of these images using QGIS, where I assigned
discrete ranges of colors. The legend of each of the windows shows the selected ranges.
Then, I stored the reference RGB values in two different arrays, one for each window. I used
these references to know the variation in the pixels. Then, to find the correct range per pixel,
I took the RGB values of the selected pixel and compared them with each of the reference ranges
using the euclidean distance in the RGB space. The closest range defined the range to which the pixel belongs.
To find the dominant value in a region, I calculated the mean RGB values, then I used those means
to find the range in which it should belong as I explained before for one pixel. This metric shows
the dominant pixels in the region.</p>
</body>
</html>