See it.
Bitmap bmp text Bitmap bmp declares a reference to a Bitmap object. At each iteration of the loop, you construct a new object, and the link begins to reference the object (as a result of the assignment).
If the link is declared after the cycle, then (starting from the second iteration), the link no longer points to the old object left over from the last iteration, and it becomes an allowed garbage collector.
If the link is declared inside the loop, then it dies at the end of each iteration, and the object again becomes accessible to the garbage collector.
Technically, the difference is that when you declare a link by loop, the old value is still available at the beginning of the loop, and the last value is available after the loop ends. Usually, such accessibility is not necessary or even harmful: you can forget to initialize the variable, and you will work with the old object instead of the new one.
Example:
Bitmap bmp = null; foreach (string fn in fileNames) { if (condition) bmp = new Bitmap(fn); // else вы работаете со старым объектом }
If bmp declared inside, the compiler will not miss it.
Therefore, it is usually recommended to declare variables in the nested block itself, wherever possible, to protect against stupid errors.
Clarification: as @Zufir correctly suggests in the comment, the link to bmp stored in a bitmapsList , so the object will not be eaten by the garbage collector in this case. But without this save, the object would be available for assembly.