У каждого потока есть очередь событий.
Выглядит примерно так
отрисовка мышки
отрисовка экрана
изменение картинки
отрисовка экрана
нажатие клавиши
нажатие мышки
отрисовка экрана
цикл
изменение картинки
изменение картинки
изменение картинки
изменение картинки
изменение картинки
изменение картинки
изменение картинки
Т.е. меняя картинку ты добавляешь это событие в конец очереди. А цикл у тебя всё продолжается и не даёт это событие исполнить. А уже как цикл отработает и твою программу отпустит, сразу происходят накопленные изменения картинки.
processEvents вызывает дальнейшую обработку событий, до конца накопленных. Т.е. при вызове будет обработаны все события из очереди, а после продолжится выполнение функции.
PS если использовать таймер(QTimer), то будет всё хоккей.