-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquantizedimage.c
188 lines (157 loc) · 5.18 KB
/
quantizedimage.c
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
/** quantizedimage.c
* The code computes the quantized image, quantizing the input image into a number of intensities
* equal to the number of threads.
*
*/
#include "common.h"
#include "quantizedimage.h"
#include "quanttree.h"
ThreadQntImgData *MakeThreadQntImgData(int numthreads)
{
ThreadQntImgData *data = malloc(numthreads *sizeof(ThreadQntImgData));
int i;
for (i=0; i<numthreads; i++)
{
data[i].self=i;
}
return(data);
}
void FreeThreadQntImgData(ThreadQntImgData *data, int numthreads)
{
free(data);
}
void RunThreadsWritingQuantizedImage(ThreadQntImgData *thdata, int nthreads)
{
int thread;
for (thread=0; thread<nthreads; ++thread)
{
pthread_create(threadID+thread, NULL, wqi, (void *) (thdata + thread));
}
for (thread=0; thread<nthreads; ++thread)
{
pthread_join(threadID[thread], NULL);
}
}
/* CreateQuantizedImage */
int CreateQuantizedImage()
{
pixel_t numRemPixels = size;
pixel_t expectedNumPixelPerQtzLev = numRemPixels/(inputQTZLEVELS);
int currentQtzLev = 0;
pixel_t px=0, count = 0;
greyval_t prevBoundGval = 0;
int idxThread = 0;
while(px<size)
{
pxStartPosition[idxThread] = px;
// iterate until the optimal number of pixels for the current thread
while(px<size && (count < expectedNumPixelPerQtzLev || currentQtzLev == inputQTZLEVELS-1))
{
gval_qu[SORTED[px]] = currentQtzLev;
count++;
prevBoundGval = gval[SORTED[px]];
px++;
}
// iterate until the next intensity change to map different intensities on different threads
while(px<size && prevBoundGval == gval[SORTED[px]])
{
gval_qu[SORTED[px]] = currentQtzLev;
count++;
px++;
}
// update thread info
pxEndPosition[idxThread] = px-1;
// work out the optimal number of pixels for the next thread
numRemPixels = numRemPixels - count;
expectedNumPixelPerQtzLev = numRemPixels/(inputQTZLEVELS-currentQtzLev);
currentQtzLev++;
idxThread++;
count=0;
}
return currentQtzLev; // return the number of quantization levels used
}
int WorkOutBoundaries()
{
pixel_t numRemPixels = size;
pixel_t expectedNumPixelPerQtzLev = numRemPixels/(inputQTZLEVELS);
//printf("Optimal number of pixels per thread = %ld\n", expectedNumPixelPerQtzLev);
int currentQtzLev = 0;
pixel_t px=0;
greyval_t prevBoundGval = 0;
int idxThread = 0;
while(px<size)
{
pxStartPosition[idxThread] = px;
px += (expectedNumPixelPerQtzLev - 1); // point to the last gvalue of that thread.
if(px<size)
{
prevBoundGval = gval[SORTED[px]];
px++;
while( (px<size) && ( (prevBoundGval == gval[SORTED[px]]) || (currentQtzLev == numQTZLEVELS-1) ) )
{
px++;
}
pxEndPosition[idxThread] = px - 1;
}
else
pxEndPosition[idxThread] = size-1;
currentQtzLev++;
idxThread++;
}
return currentQtzLev; // return the number of quantization levels used
}
void *wqi(void *arg)
{
ThreadQntImgData *threfdata = (ThreadQntImgData *) arg;
int self = threfdata->self;
pixel_t i;
for(i=pxStartPosition[self]; i <= pxEndPosition[self]; i++)
{
gval_qu[SORTED[i]] = self;
}
return NULL;
}
void CreateQuantizedImageInParallel(int numQtzLevsUsed)
{
ThreadQntImgData *thqntimgdata = MakeThreadQntImgData(numQtzLevsUsed);
RunThreadsWritingQuantizedImage(thqntimgdata, numQtzLevsUsed);
FreeThreadQntImgData(thqntimgdata, numQtzLevsUsed);
}
void CalculateQuantizedImage()
{
if(is3D && nthreads > depth)
{
printf("Exit. Number of threads must be equal to or larger than the third dimension of the cube.\n");
exit(0);
}
/* create the quantized image */
gval_qu = malloc(size*sizeof(int));
if (gval_qu==NULL)
{
fprintf(stderr, "out of memory! \n");
free(gval_qu);
exit(0);
}
pxStartPosition = calloc(inputQTZLEVELS, sizeof(pixel_t));
pxEndPosition = calloc(inputQTZLEVELS, sizeof(pixel_t));
// First Way: in parallel
numQTZLEVELS = WorkOutBoundaries();
if(numQTZLEVELS != inputQTZLEVELS)
{
printf("Number of computed quantized levels %d differs from the input parameter %d. Trying an other method (sacrifice load balance).\n", numQTZLEVELS, inputQTZLEVELS);
// Second Way: use the old sequential (worst load balance)
numQTZLEVELS = CreateQuantizedImage();
if(numQTZLEVELS != inputQTZLEVELS)
{
printf("ERROR: input quantized levels = %d, but actually used %d ! ", inputQTZLEVELS, numQTZLEVELS);
printf("Exiting: please reduce the number of threads!\n");
//printf("Sacrifice load balance and maintain the input number of quantization levels using e.g. \"CreateQuantizedImage()\".\n");
exit(0);
}
else {printf("Number of threads now equal to %d.\n", numQTZLEVELS);}
return;
}
// if everything goes good:
CreateQuantizedImageInParallel(numQTZLEVELS);
return;
}