С вашим кодом есть две проблемы:
Вы не устанавливаете выходное изображение в ноль, прежде чем добавлять к нему значения.Следовательно, вы вычисляете «вход + отфильтрованный вход», а не просто «отфильтрованный вход».
Предполагая, что kernel
имеет довольно маленькие значения, «входной пиксель * значение ядра» будетскорее всего, получится небольшое число, которое округляется вниз при записи в uchar
.Сложив каждое из этих значений для ядра, вы получите слишком низкий результат.
Я рекомендую вам сделать это:
double res = 0;
for(int x = 0; x < W; ++x){
int xx = W - 1 - x;
for(int y = 0; y < W; ++y){
int yy = W - 1 - y;
int ii = i + (x - kCenterX);
int jj = j + (y - kCenterY);
if( ii >= 0 && ii < image.rows && jj >= 0 && jj < image.cols) {
res += image.at<uchar>(Point(jj, ii)) * kernel[xx][yy];
}
}
}
filtered_image.at<uchar>(Point(j, i)) = res;
Это решает обе проблемы одновременно.Кроме того, это должно быть немного быстрее, потому что доступ к выходному изображению немного перегружен.
Для гораздо более высоких скоростей учтите, что проверка на чтение за пределами считывания (if
во внутреннем цикле)) значительно замедляет код и совершенно не нужен большинству пикселей (так как несколько пикселей находятся у края изображения).Вместо этого вы можете разбить свои циклы на [0,kCenterX]
, [kCenterX,image.rows-kCenterX]
и [image.rows-kCenterX,image.rows]
.Средний цикл, который обычно является самым большим, не должен проверять наличие за пределами чтения.