Use RAII to manage the GIL

This commit is contained in:
Kovid Goyal 2016-05-08 14:34:59 +05:30
parent 1055797da4
commit 2db5e10bbd
3 changed files with 18 additions and 28 deletions

View File

@ -87,6 +87,7 @@ static unsigned int read_border_row(const QImage &img, const unsigned int width,
} }
QImage remove_borders(const QImage &image, double fuzz) { QImage remove_borders(const QImage &image, double fuzz) {
ScopedGILRelease PyGILRelease;
int *buf = NULL; int *buf = NULL;
QImage img = image, timg; QImage img = image, timg;
QTransform transpose; QTransform transpose;
@ -100,7 +101,6 @@ QImage remove_borders(const QImage &image, double fuzz) {
buf = vbuf.data(); buf = vbuf.data();
fuzz /= 255; fuzz /= 255;
Py_BEGIN_ALLOW_THREADS;
top_border = read_border_row(img, width, height, buf, fuzz, true); top_border = read_border_row(img, width, height, buf, fuzz, true);
if (top_border < height - 1) { if (top_border < height - 1) {
bottom_border = read_border_row(img, width, height, buf, fuzz, false); bottom_border = read_border_row(img, width, height, buf, fuzz, false);
@ -123,7 +123,6 @@ QImage remove_borders(const QImage &image, double fuzz) {
} }
} }
} }
Py_END_ALLOW_THREADS;
if (bad_alloc) throw std::bad_alloc(); if (bad_alloc) throw std::bad_alloc();
return img; return img;
@ -131,12 +130,12 @@ QImage remove_borders(const QImage &image, double fuzz) {
// }}} // }}}
QImage grayscale(const QImage &image) { // {{{ QImage grayscale(const QImage &image) { // {{{
ScopedGILRelease PyGILRelease;
QImage img = image; QImage img = image;
QRgb *row = NULL, *pixel = NULL; QRgb *row = NULL, *pixel = NULL;
int r = 0, gray = 0, width = img.width(), height = img.height(); int r = 0, gray = 0, width = img.width(), height = img.height();
ENSURE32(img); ENSURE32(img);
Py_BEGIN_ALLOW_THREADS;
for (r = 0; r < height; r++) { for (r = 0; r < height; r++) {
row = reinterpret_cast<QRgb*>(img.scanLine(r)); row = reinterpret_cast<QRgb*>(img.scanLine(r));
for (pixel = row; pixel < row + width; pixel++) { for (pixel = row; pixel < row + width; pixel++) {
@ -144,7 +143,6 @@ QImage grayscale(const QImage &image) { // {{{
*pixel = QColor(gray, gray, gray).rgba(); *pixel = QColor(gray, gray, gray).rgba();
} }
} }
Py_END_ALLOW_THREADS;
return img; return img;
} // }}} } // }}}
@ -178,7 +176,6 @@ static QImage convolve(const QImage &image, int matrix_size, float *matrix) {
scanblock = buf1.data(); scanblock = buf1.data();
buf2.resize(matrix_size * matrix_size); buf2.resize(matrix_size * matrix_size);
normalize_matrix = buf2.data(); normalize_matrix = buf2.data();
Py_BEGIN_ALLOW_THREADS;
// create normalized matrix // create normalized matrix
normalize = 0.0; normalize = 0.0;
@ -267,7 +264,6 @@ static QImage convolve(const QImage &image, int matrix_size, float *matrix) {
(unsigned char)b, qAlpha(*src++)); (unsigned char)b, qAlpha(*src++));
} }
} }
Py_END_ALLOW_THREADS;
return buffer; return buffer;
} }
@ -284,7 +280,6 @@ static int default_convolve_matrix_size(const float radius, const float sigma, c
if(radius > 0.0) if(radius > 0.0)
return((int)(2.0*ceil(radius)+1.0)); return((int)(2.0*ceil(radius)+1.0));
Py_BEGIN_ALLOW_THREADS;
matrix_size = 5; matrix_size = 5;
do{ do{
normalize = 0.0; normalize = 0.0;
@ -296,13 +291,13 @@ static int default_convolve_matrix_size(const float radius, const float sigma, c
} while((int)(max*value) > 0); } while((int)(max*value) > 0);
matrix_size-=4; matrix_size-=4;
Py_END_ALLOW_THREADS;
return(matrix_size); return(matrix_size);
} }
// }}} // }}}
QImage gaussian_sharpen(const QImage &img, const float radius, const float sigma, const bool high_quality) { // {{{ QImage gaussian_sharpen(const QImage &img, const float radius, const float sigma, const bool high_quality) { // {{{
ScopedGILRelease PyGILRelease;
int matrix_size = default_convolve_matrix_size(radius, sigma, high_quality); int matrix_size = default_convolve_matrix_size(radius, sigma, high_quality);
int len = matrix_size*matrix_size; int len = matrix_size*matrix_size;
QVector<float> buf = QVector<float>(len); QVector<float> buf = QVector<float>(len);
@ -313,7 +308,6 @@ QImage gaussian_sharpen(const QImage &img, const float radius, const float sigma
int half = matrix_size/2; int half = matrix_size/2;
int x, y, i=0, j=half; int x, y, i=0, j=half;
float normalize=0.0; float normalize=0.0;
Py_BEGIN_ALLOW_THREADS;
for(y=(-half); y <= half; ++y, --j){ for(y=(-half); y <= half; ++y, --j){
for(x=(-half); x <= half; ++x, ++i){ for(x=(-half); x <= half; ++x, ++i){
alpha = std::exp(-((float)x*x+y*y)/sigma2); alpha = std::exp(-((float)x*x+y*y)/sigma2);
@ -323,14 +317,12 @@ QImage gaussian_sharpen(const QImage &img, const float radius, const float sigma
} }
matrix[i/2]=(-2.0)*normalize; matrix[i/2]=(-2.0)*normalize;
Py_END_ALLOW_THREADS;
QImage result(convolve(img, matrix_size, matrix)); QImage result(convolve(img, matrix_size, matrix));
return(result); return(result);
} // }}} } // }}}
// gaussian_blur() {{{ // gaussian_blur() {{{
static void get_blur_kernel(int &kernel_width, const float sigma, QVector<float> &kernel) static void get_blur_kernel(int &kernel_width, const float sigma, QVector<float> &kernel) {
{
#define KernelRank 3 #define KernelRank 3
float alpha, normalize; float alpha, normalize;
@ -341,7 +333,6 @@ static void get_blur_kernel(int &kernel_width, const float sigma, QVector<float>
if(kernel_width == 0) kernel_width = 3; if(kernel_width == 0) kernel_width = 3;
kernel.resize(kernel_width + 1); kernel.resize(kernel_width + 1);
Py_BEGIN_ALLOW_THREADS;
kernel.fill(0); kernel.fill(0);
bias = KernelRank*kernel_width/2; bias = KernelRank*kernel_width/2;
for(i=(-bias); i <= bias; ++i){ for(i=(-bias); i <= bias; ++i){
@ -354,7 +345,6 @@ static void get_blur_kernel(int &kernel_width, const float sigma, QVector<float>
normalize += kernel[i]; normalize += kernel[i];
for(i=0; i < kernel_width; ++i) for(i=0; i < kernel_width; ++i)
kernel[i] /= normalize; kernel[i] /= normalize;
Py_END_ALLOW_THREADS;
} }
static void blur_scan_line(const float* kernel, const int kern_width, const QRgb *source, QRgb *destination, const int columns, const int offset) { static void blur_scan_line(const float* kernel, const int kern_width, const QRgb *source, QRgb *destination, const int columns, const int offset) {
@ -367,7 +357,6 @@ static void blur_scan_line(const float* kernel, const int kern_width, const QRgb
memset(&zero, 0, sizeof(FloatPixel)); memset(&zero, 0, sizeof(FloatPixel));
if(kern_width > columns){ if(kern_width > columns){
Py_BEGIN_ALLOW_THREADS;
for(dest=destination, x=0; x < columns; ++x, dest+=offset){ for(dest=destination, x=0; x < columns; ++x, dest+=offset){
aggregate = zero; aggregate = zero;
scale = 0.0; scale = 0.0;
@ -390,11 +379,9 @@ static void blur_scan_line(const float* kernel, const int kern_width, const QRgb
(unsigned char)(scale*(aggregate.blue+0.5)), (unsigned char)(scale*(aggregate.blue+0.5)),
(unsigned char)(scale*(aggregate.alpha+0.5))); (unsigned char)(scale*(aggregate.alpha+0.5)));
} }
Py_END_ALLOW_THREADS;
return; return;
} }
Py_BEGIN_ALLOW_THREADS;
// blur // blur
for(dest=destination, x=0; x < kern_width/2; ++x, dest+=offset){ for(dest=destination, x=0; x < kern_width/2; ++x, dest+=offset){
aggregate = zero; // put this stuff in loop initializer once tested aggregate = zero; // put this stuff in loop initializer once tested
@ -447,10 +434,10 @@ static void blur_scan_line(const float* kernel, const int kern_width, const QRgb
(unsigned char)(scale*(aggregate.blue+0.5)), (unsigned char)(scale*(aggregate.blue+0.5)),
(unsigned char)(scale*(aggregate.alpha+0.5))); (unsigned char)(scale*(aggregate.alpha+0.5)));
} }
Py_END_ALLOW_THREADS;
} }
QImage gaussian_blur(const QImage &image, const float radius, const float sigma) { QImage gaussian_blur(const QImage &image, const float radius, const float sigma) {
ScopedGILRelease PyGILRelease;
int kern_width, x, y, w, h; int kern_width, x, y, w, h;
QRgb *src; QRgb *src;
QImage img(image); QImage img(image);
@ -570,6 +557,7 @@ static inline void hull(const int x_offset, const int y_offset, const int w, con
} }
QImage despeckle(const QImage &image) { QImage despeckle(const QImage &image) {
ScopedGILRelease PyGILRelease;
int length, x, y, j, i; int length, x, y, j, i;
QRgb *dest; QRgb *dest;
const QRgb *src; const QRgb *src;
@ -585,11 +573,9 @@ QImage despeckle(const QImage &image) {
length = (img.width()+2)*(img.height()+2); length = (img.width()+2)*(img.height()+2);
QVector<unsigned char> pixels(length), buffer(length); QVector<unsigned char> pixels(length), buffer(length);
Py_BEGIN_ALLOW_THREADS;
DESPECKLE_CHANNEL(qRed, qRgba(pixels[j], qGreen(*dest), qBlue(*dest), qAlpha(*dest))) DESPECKLE_CHANNEL(qRed, qRgba(pixels[j], qGreen(*dest), qBlue(*dest), qAlpha(*dest)))
DESPECKLE_CHANNEL(qGreen, qRgba(qRed(*dest), pixels[j], qBlue(*dest), qAlpha(*dest))) DESPECKLE_CHANNEL(qGreen, qRgba(qRed(*dest), pixels[j], qBlue(*dest), qAlpha(*dest)))
DESPECKLE_CHANNEL(qBlue, qRgba(qRed(*dest), qGreen(*dest), pixels[j], qAlpha(*dest))) DESPECKLE_CHANNEL(qBlue, qRgba(qRed(*dest), qGreen(*dest), pixels[j], qAlpha(*dest)))
Py_END_ALLOW_THREADS;
return(img); return(img);
} }
@ -604,6 +590,7 @@ static inline unsigned int BYTE_MUL(unsigned int x, unsigned int a) {
} }
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) {
ScopedGILRelease PyGILRelease;
QImage img(image); QImage img(image);
unsigned int cw = canvas.width(), ch = canvas.height(), iw = img.width(), ih = img.height(), r, c, right = 0, bottom = 0, height, width, s; unsigned int cw = canvas.width(), ch = canvas.height(), iw = img.width(), ih = img.height(), r, c, right = 0, bottom = 0, height, width, s;
const QRgb* src; const QRgb* src;
@ -624,7 +611,6 @@ void overlay(const QImage &image, QImage &canvas, unsigned int left, unsigned in
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
if (img.isNull()) throw std::bad_alloc(); if (img.isNull()) throw std::bad_alloc();
} }
Py_BEGIN_ALLOW_THREADS;
for (r = 0; r < height; r++) { for (r = 0; r < height; r++) {
src = reinterpret_cast<const QRgb*>(img.constScanLine(r)); src = reinterpret_cast<const QRgb*>(img.constScanLine(r));
dest = reinterpret_cast<QRgb*>(canvas.scanLine(r + top)); dest = reinterpret_cast<QRgb*>(canvas.scanLine(r + top));
@ -639,21 +625,19 @@ void overlay(const QImage &image, QImage &canvas, unsigned int left, unsigned in
else if (s != 0) dest[left+c] = s + BYTE_MUL(dest[left+c], qAlpha(~s)); else if (s != 0) dest[left+c] = s + BYTE_MUL(dest[left+c], qAlpha(~s));
} }
} }
Py_END_ALLOW_THREADS;
} else { } else {
ENSURE32(img); ENSURE32(img);
Py_BEGIN_ALLOW_THREADS;
for (r = 0; r < bottom; r++) { for (r = 0; r < bottom; r++) {
src = reinterpret_cast<const QRgb*>(img.constScanLine(r)); src = reinterpret_cast<const QRgb*>(img.constScanLine(r));
dest = reinterpret_cast<QRgb*>(canvas.scanLine(r + top)); dest = reinterpret_cast<QRgb*>(canvas.scanLine(r + top));
memcpy(dest + left, src, (right - left) * sizeof(QRgb)); memcpy(dest + left, src, (right - left) * sizeof(QRgb));
} }
Py_END_ALLOW_THREADS;
} }
} // }}} } // }}}
QImage normalize(const QImage &image) { // {{{ QImage normalize(const QImage &image) { // {{{
ScopedGILRelease PyGILRelease;
IntegerPixel intensity; IntegerPixel intensity;
HistogramListItem histogram[256] = {{0, 0, 0, 0}}; HistogramListItem histogram[256] = {{0, 0, 0, 0}};
CharPixel normalize_map[256] = {{0, 0, 0, 0}}; CharPixel normalize_map[256] = {{0, 0, 0, 0}};
@ -667,7 +651,6 @@ QImage normalize(const QImage &image) { // {{{
ENSURE32(img); ENSURE32(img);
count = img.width()*img.height(); count = img.width()*img.height();
Py_BEGIN_ALLOW_THREADS;
// form histogram // form histogram
dest = (QRgb *)img.bits(); dest = (QRgb *)img.bits();
@ -766,11 +749,11 @@ QImage normalize(const QImage &image) { // {{{
*dest++ = qRgba(r, g, b, qAlpha(pixel)); *dest++ = qRgba(r, g, b, qAlpha(pixel));
} }
Py_END_ALLOW_THREADS;
return img; return img;
} // }}} } // }}}
QImage oil_paint(const QImage &image, const float radius, const bool high_quality) { // {{{ QImage oil_paint(const QImage &image, const float radius, const bool high_quality) { // {{{
ScopedGILRelease PyGILRelease;
int matrix_size = default_convolve_matrix_size(radius, 0.5, 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 i, x, y, w, h, matrix_x, matrix_y;
int edge = matrix_size/2; int edge = matrix_size/2;
@ -789,7 +772,6 @@ QImage oil_paint(const QImage &image, const float radius, const bool high_qualit
buf.resize(matrix_size); buf.resize(matrix_size);
scanblock = buf.data(); scanblock = buf.data();
Py_BEGIN_ALLOW_THREADS;
for(y=0; y < h; ++y){ for(y=0; y < h; ++y){
dest = reinterpret_cast<QRgb *>(buffer.scanLine(y)); dest = reinterpret_cast<QRgb *>(buffer.scanLine(y));
@ -880,6 +862,5 @@ QImage oil_paint(const QImage &image, const float radius, const bool high_qualit
} }
} }
Py_END_ALLOW_THREADS;
return(buffer); return(buffer);
} // }}} } // }}}

View File

@ -19,3 +19,11 @@ void overlay(const QImage &image, QImage &canvas, unsigned int left, unsigned in
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); QImage oil_paint(const QImage &image, const float radius=-1, const bool high_quality=true);
QImage quantize(const QImage &image, unsigned int maximum_colors=256, bool dither=true); QImage quantize(const QImage &image, unsigned int maximum_colors=256, bool dither=true);
class ScopedGILRelease {
public:
inline ScopedGILRelease() { this->thread_state = PyEval_SaveThread(); }
inline ~ScopedGILRelease() { PyEval_RestoreThread(this->thread_state); this->thread_state = NULL; }
private:
PyThreadState * thread_state;
};

View File

@ -135,6 +135,7 @@ public:
}; };
QImage quantize(const QImage &image, unsigned int maximum_colors, bool dither) { QImage quantize(const QImage &image, unsigned int maximum_colors, bool dither) {
ScopedGILRelease PyGILRelease;
size_t depth = 0; size_t depth = 0;
int iwidth = image.width(), iheight = image.height(), r, c; int iwidth = image.width(), iheight = image.height(), r, c;
QImage img(image), ans(iwidth, iheight, QImage::Format_Indexed8); QImage img(image), ans(iwidth, iheight, QImage::Format_Indexed8);