mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement oil_paint()
This commit is contained in:
parent
c99232091f
commit
b5bc34e0fe
@ -782,3 +782,118 @@ QImage normalize(const QImage &image) { // {{{
|
|||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
return img;
|
return img;
|
||||||
} // }}}
|
} // }}}
|
||||||
|
|
||||||
|
QImage oil_paint(const QImage &image, const float radius, const bool high_quality) {
|
||||||
|
int matrix_size = default_convolve_matrix_size(radius, 0.5, high_quality);
|
||||||
|
int i, x, y, w, h, matrix_x, matrix_y;
|
||||||
|
int edge = matrix_size/2;
|
||||||
|
unsigned int max, value;
|
||||||
|
QRgb *dest, *s, **scanblock;
|
||||||
|
QImage img(image);
|
||||||
|
|
||||||
|
w = img.width();
|
||||||
|
h = img.height();
|
||||||
|
if(w < 3 || h < 3) throw std::out_of_range("Image is too small");
|
||||||
|
|
||||||
|
ENSURE32(img);
|
||||||
|
QImage buffer(w, h, img.format());
|
||||||
|
|
||||||
|
scanblock = new QRgb* [matrix_size];
|
||||||
|
unsigned int *histogram = new unsigned int[256];
|
||||||
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
|
|
||||||
|
for(y=0; y < h; ++y){
|
||||||
|
dest = reinterpret_cast<QRgb *>(buffer.scanLine(y));
|
||||||
|
// Read in scanlines to pixel neighborhood. If the scanline is outside
|
||||||
|
// the image use the top or bottom edge.
|
||||||
|
for(x=y-edge, i=0; x <= y+edge; ++i, ++x)
|
||||||
|
scanblock[i] = reinterpret_cast<QRgb *>(img.scanLine((x < 0) ? 0 : (x > h-1) ? h-1 : x));
|
||||||
|
|
||||||
|
// Now we are about to start processing scanlines. First handle the
|
||||||
|
// part where the pixel neighborhood extends off the left edge.
|
||||||
|
for(x=0; x-edge < 0 ; ++x){
|
||||||
|
(void)memset(histogram, 0, 256*sizeof(unsigned int));
|
||||||
|
max = 0;
|
||||||
|
for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
|
||||||
|
s = scanblock[matrix_y];
|
||||||
|
matrix_x = -edge;
|
||||||
|
while(x+matrix_x < 0){
|
||||||
|
value = qGray(*s);
|
||||||
|
histogram[value]++;
|
||||||
|
if(histogram[value] > max){
|
||||||
|
max = histogram[value];
|
||||||
|
*dest = *s;
|
||||||
|
}
|
||||||
|
++matrix_x;
|
||||||
|
}
|
||||||
|
while(matrix_x <= edge){
|
||||||
|
value = qGray(*s);
|
||||||
|
histogram[value]++;
|
||||||
|
if(histogram[value] > max){
|
||||||
|
max = histogram[value];
|
||||||
|
*dest = *s;
|
||||||
|
}
|
||||||
|
++matrix_x; ++s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, now process the middle part where the entire neighborhood
|
||||||
|
// is on the image.
|
||||||
|
for(; x+edge < w; ++x){
|
||||||
|
(void)memset(histogram, 0, 256*sizeof(unsigned int));
|
||||||
|
max = 0;
|
||||||
|
for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
|
||||||
|
s = scanblock[matrix_y] + (x-edge);
|
||||||
|
for(matrix_x = -edge; matrix_x <= edge; ++matrix_x, ++s){
|
||||||
|
value = qGray(*s);
|
||||||
|
histogram[value]++;
|
||||||
|
if(histogram[value] > max){
|
||||||
|
max = histogram[value];
|
||||||
|
*dest = *s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally process the right part where the neighborhood extends off
|
||||||
|
// the right edge of the image
|
||||||
|
for(; x < w; ++x){
|
||||||
|
(void)memset(histogram, 0, 256*sizeof(unsigned int));
|
||||||
|
max = 0;
|
||||||
|
for(matrix_y = 0; matrix_y < matrix_size; ++matrix_y){
|
||||||
|
s = scanblock[matrix_y];
|
||||||
|
s += x-edge;
|
||||||
|
matrix_x = -edge;
|
||||||
|
while(x+matrix_x < w){
|
||||||
|
value = qGray(*s);
|
||||||
|
histogram[value]++;
|
||||||
|
if(histogram[value] > max){
|
||||||
|
max = histogram[value];
|
||||||
|
*dest = *s;
|
||||||
|
}
|
||||||
|
++matrix_x, ++s;
|
||||||
|
}
|
||||||
|
--s;
|
||||||
|
while(matrix_x <= edge){
|
||||||
|
value = qGray(*s);
|
||||||
|
histogram[value]++;
|
||||||
|
if(histogram[value] > max){
|
||||||
|
max = histogram[value];
|
||||||
|
*dest = *s;
|
||||||
|
}
|
||||||
|
++matrix_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++dest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] histogram;
|
||||||
|
delete[] scanblock;
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
return(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -17,3 +17,4 @@ QImage gaussian_blur(const QImage &img, const float radius, const float sigma);
|
|||||||
QImage despeckle(const QImage &image);
|
QImage despeckle(const QImage &image);
|
||||||
void overlay(const QImage &image, QImage &canvas, unsigned int left, unsigned int top);
|
void overlay(const QImage &image, QImage &canvas, unsigned int left, unsigned int top);
|
||||||
QImage normalize(const QImage &image);
|
QImage normalize(const QImage &image);
|
||||||
|
QImage oil_paint(const QImage &image, const float radius=-1, const bool high_quality=true);
|
||||||
|
@ -65,3 +65,10 @@ QImage normalize(const QImage &image);
|
|||||||
sipRes = new QImage(normalize(*a0));
|
sipRes = new QImage(normalize(*a0));
|
||||||
IMAGEOPS_SUFFIX
|
IMAGEOPS_SUFFIX
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
QImage oil_paint(const QImage &image, const float radius=-1, const bool high_quality=true);
|
||||||
|
%MethodCode
|
||||||
|
IMAGEOPS_PREFIX
|
||||||
|
sipRes = new QImage(oil_paint(*a0, a1, a2));
|
||||||
|
IMAGEOPS_SUFFIX
|
||||||
|
%End
|
||||||
|
@ -244,6 +244,11 @@ def despeckle(img):
|
|||||||
raise RuntimeError(imageops_err)
|
raise RuntimeError(imageops_err)
|
||||||
return imageops.despeckle(image_from_data(img))
|
return imageops.despeckle(image_from_data(img))
|
||||||
|
|
||||||
|
def oil_paint(img, radius=-1, high_quality=True):
|
||||||
|
if imageops is None:
|
||||||
|
raise RuntimeError(imageops_err)
|
||||||
|
return imageops.oil_paint(image_from_data(img), radius, high_quality)
|
||||||
|
|
||||||
def normalize(img):
|
def normalize(img):
|
||||||
if imageops is None:
|
if imageops is None:
|
||||||
raise RuntimeError(imageops_err)
|
raise RuntimeError(imageops_err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user